add oauth flow routes
This commit is contained in:
+139
-1
@@ -1,6 +1,17 @@
|
||||
package google
|
||||
|
||||
import "net/url"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go-cal/pkg/config"
|
||||
"go-cal/pkg/types"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
var baseURL = "https://www.googleapis.com/"
|
||||
|
||||
@@ -22,3 +33,130 @@ func getHeaders() map[string]string {
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
// OAuthExchangeCodeToToken -
|
||||
func OAuthExchangeCodeToToken(code string) (token types.GoogleAuthToken, err error) {
|
||||
conf := config.Get()
|
||||
if conf == nil {
|
||||
return token, errors.New("config not init")
|
||||
}
|
||||
|
||||
u, err := url.Parse(conf.Google.TokenURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
qs := url.Values{}
|
||||
qs.Set("code", code)
|
||||
qs.Set("client_id", conf.Google.ClientID)
|
||||
qs.Set("client_secret", conf.Google.ClientSecret)
|
||||
qs.Set("redirect_uri", conf.Google.RedirectURL)
|
||||
qs.Set("grant_type", "authorization_code")
|
||||
|
||||
reader := bytes.NewReader([]byte(qs.Encode()))
|
||||
|
||||
req, err := http.NewRequest("POST", fmt.Sprintf("%s", u.String()), reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(b, &token)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OAuthRefreshToken -
|
||||
func OAuthRefreshToken(refreshToken string) (token string, expiresIn int64, err error) {
|
||||
if len(refreshToken) == 0 {
|
||||
return "", 0, errors.New("refresh token is empty")
|
||||
}
|
||||
|
||||
conf := config.Get()
|
||||
if conf == nil {
|
||||
return "", 0, errors.New("config not init")
|
||||
}
|
||||
|
||||
u, err := url.Parse(conf.Google.TokenURL)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
qs := url.Values{}
|
||||
qs.Set("client_id", conf.Google.ClientID)
|
||||
qs.Set("client_secret", conf.Google.ClientSecret)
|
||||
qs.Set("grant_type", "refresh_token")
|
||||
|
||||
reader := bytes.NewReader([]byte(qs.Encode()))
|
||||
|
||||
req, err := http.NewRequest("POST", u.String(), reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var tokenData types.GoogleAuthToken
|
||||
err = json.NewDecoder(resp.Body).Decode(&tokenData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tokenData.ExpiresIn += time.Now().Unix()
|
||||
|
||||
return tokenData.AccessToken, tokenData.ExpiresIn, nil
|
||||
}
|
||||
|
||||
// GetTokenInfo -
|
||||
func GetTokenInfo(token string) (expire int64, err error) {
|
||||
u, err := url.Parse("https://oauth2.googleapis.com/tokeninfo")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
body := struct {
|
||||
Azp string `json:"azp"`
|
||||
Aud string `json:"aud"`
|
||||
Scope string `json:"scope"`
|
||||
Exp json.Number `json:"exp"`
|
||||
ExpiresIn json.Number `json:"expires_in"`
|
||||
AccessType string `json:"access_type"`
|
||||
}{}
|
||||
|
||||
qs := url.Values{}
|
||||
qs.Set("access_token", token)
|
||||
|
||||
resp, err := http.Get(fmt.Sprintf("%s?%s", u.String(), qs.Encode()))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
err = json.NewDecoder(resp.Body).Decode(&body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
expTime, err := body.Exp.Int64()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return expTime, nil
|
||||
}
|
||||
|
||||
+15
-3
@@ -13,13 +13,25 @@ import (
|
||||
|
||||
// Google config
|
||||
type Google struct {
|
||||
APIKey string `yaml:"api_key" env:"GOOGLE_API_KEY"`
|
||||
APIKey string `yaml:"api_key" env:"GOOGLE_API_KEY"`
|
||||
ClientID string `yaml:"client_id" env:"GOOGLE_CLIENT_ID"`
|
||||
AuthURL string `yaml:"auth_url" env:"GOOGLE_AUTH_URL"`
|
||||
TokenURL string `yaml:"token_url" env:"GOOGLE_TOKEN_URL"`
|
||||
ClientSecret string `yaml:"client_secret" env:"GOOGLE_CLIENT_SECRET"`
|
||||
RedirectURL string `yaml:"redirect_url" env:"GOOGLE_REDIRECT_URL"`
|
||||
Scopes []string `yaml:"scopes" env:"GOOGLE_SCOPES"`
|
||||
}
|
||||
|
||||
// Storage struct
|
||||
type Storage struct {
|
||||
Path string `yaml:"path" env:"STORAGE_FILE_PATH"`
|
||||
}
|
||||
|
||||
// Config main struct
|
||||
type Config struct {
|
||||
Port int `yaml:"port" env:"PORT"`
|
||||
Google Google `yaml:"google"`
|
||||
Port int `yaml:"port" env:"PORT"`
|
||||
Google Google `yaml:"google"`
|
||||
Storage Storage `yaml:"storage"`
|
||||
}
|
||||
|
||||
var conf *Config
|
||||
|
||||
+24
-9
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
|
||||
"git.trj.tw/golang/utils"
|
||||
)
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
type Storage struct {
|
||||
m map[string]interface{}
|
||||
filePath string
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
var s *Storage
|
||||
@@ -30,24 +32,31 @@ func New() *Storage {
|
||||
func Get() *Storage { return s }
|
||||
|
||||
// Load storage data from file
|
||||
func (p *Storage) Load(filePath string) (err error) {
|
||||
func (p *Storage) Load(filePath string, ignoreNotExist bool) (err error) {
|
||||
filePath = utils.ParsePath(filePath)
|
||||
if !utils.CheckExists(filePath, false) {
|
||||
exist := utils.CheckExists(filePath, false)
|
||||
if !exist && !ignoreNotExist {
|
||||
return errors.New("storage file not found")
|
||||
}
|
||||
p.filePath = filePath
|
||||
|
||||
b, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if exist {
|
||||
b, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(b, &p.m)
|
||||
if err := json.Unmarshal(b, &p.m); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Storage) Write() (err error) {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
b, err := json.Marshal(p.m)
|
||||
if err != nil {
|
||||
return
|
||||
@@ -64,7 +73,13 @@ func (p *Storage) Get(key string) (data interface{}, ok bool) {
|
||||
}
|
||||
|
||||
// Set data by key
|
||||
func (p *Storage) Set(key string, value interface{}) { p.m[key] = value }
|
||||
func (p *Storage) Set(key string, value interface{}) {
|
||||
p.m[key] = value
|
||||
_ = p.Write()
|
||||
}
|
||||
|
||||
// Delete data by key
|
||||
func (p *Storage) Delete(key string) { delete(p.m, key) }
|
||||
func (p *Storage) Delete(key string) {
|
||||
delete(p.m, key)
|
||||
_ = p.Write()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package types
|
||||
|
||||
// GoogleAuthToken -
|
||||
type GoogleAuthToken struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
ExpiresIn int64 `json:"expires_in"`
|
||||
TokenType string `json:"token_type"`
|
||||
}
|
||||
Reference in New Issue
Block a user