92 lines
1.8 KiB
Go
92 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
|
|
"golang.org/x/oauth2"
|
|
"golang.org/x/oauth2/google"
|
|
"google.golang.org/api/calendar/v3"
|
|
)
|
|
|
|
type GCal struct {
|
|
httpc interface {
|
|
Do(*http.Request) (*http.Response, error)
|
|
}
|
|
}
|
|
|
|
func NewGCal() *GCal {
|
|
return &GCal{}
|
|
}
|
|
|
|
func (gcal *GCal) Login(ctx context.Context) error {
|
|
token, err := gcal.getToken(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
conf, err := gcal.oauth2Config()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
gcal.httpc = conf.Client(ctx, &token)
|
|
return nil
|
|
}
|
|
|
|
func (gcal *GCal) getToken(ctx context.Context) (oauth2.Token, error) {
|
|
var token oauth2.Token
|
|
if b, _ := os.ReadFile(gcal.tokenFile()); len(b) == 0 {
|
|
} else if err := json.Unmarshal(b, &token); err != nil {
|
|
return token, nil
|
|
}
|
|
token, err := gcal.newToken(ctx)
|
|
if err != nil {
|
|
return token, err
|
|
}
|
|
b, _ := json.Marshal(token)
|
|
return token, os.WriteFile(gcal.tokenFile(), b, os.ModePerm)
|
|
}
|
|
|
|
func (gcal *GCal) newToken(ctx context.Context) (oauth2.Token, error) {
|
|
conf, err := gcal.oauth2Config()
|
|
if err != nil {
|
|
return oauth2.Token{}, err
|
|
}
|
|
|
|
u := conf.AuthCodeURL("state-token", oauth2.AccessTypeOffline)
|
|
fmt.Printf("visit %s\n", u)
|
|
var code string
|
|
if _, err := fmt.Scan(&code); err != nil {
|
|
return oauth2.Token{}, err
|
|
}
|
|
|
|
token, err := conf.Exchange(ctx, code)
|
|
if err != nil {
|
|
return oauth2.Token{}, err
|
|
}
|
|
|
|
return *token, nil
|
|
}
|
|
|
|
func (gcal *GCal) tokenFile() string {
|
|
return path.Join(os.Getenv("HOME"), "timer.gcal")
|
|
}
|
|
|
|
func (gcal *GCal) oauth2Config() (*oauth2.Config, error) {
|
|
b, err := os.ReadFile(path.Join(os.Getenv("HOME"), ".config", "gcloud", "application_default_credentials.json"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
conf, err := google.ConfigFromJSON(b, calendar.CalendarReadonlyScope)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return conf, nil
|
|
}
|