95 lines
2.3 KiB
Go
95 lines
2.3 KiB
Go
package auth
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
|
|
"git.directme.in/Joren/CanvasArchiver/internal/config"
|
|
"git.directme.in/Joren/CanvasArchiver/internal/models"
|
|
)
|
|
|
|
type Authenticator struct {
|
|
HTTPClient *http.Client
|
|
}
|
|
|
|
func NewAuthenticator(client *http.Client) *Authenticator {
|
|
return &Authenticator{
|
|
HTTPClient: client,
|
|
}
|
|
}
|
|
|
|
func (a *Authenticator) GetAccessToken() (string, error) {
|
|
creds, err := LoadCredentials()
|
|
if err != nil {
|
|
|
|
fmt.Println("--- Initial Canvas Login Required ---")
|
|
fmt.Printf("Visit: %s/login/oauth2/auth?client_id=%s&response_type=code&redirect_uri=%s\n",
|
|
config.BaseURL, config.ClientID, url.QueryEscape(config.RedirectURI))
|
|
fmt.Print("Enter Code: ")
|
|
var code string
|
|
fmt.Scanln(&code)
|
|
|
|
tr, err := a.doTokenRequest(url.Values{
|
|
"grant_type": {"authorization_code"},
|
|
"client_id": {config.ClientID},
|
|
"client_secret": {config.ClientSecret},
|
|
"redirect_uri": {config.RedirectURI},
|
|
"code": {code},
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
SaveCredentials(&models.Credentials{RefreshToken: tr.RefreshToken})
|
|
fmt.Println("[+] Login successful.")
|
|
return tr.AccessToken, nil
|
|
}
|
|
|
|
fmt.Println("[*] Reusing saved refresh token...")
|
|
tr, err := a.doTokenRequest(url.Values{
|
|
"grant_type": {"refresh_token"},
|
|
"client_id": {config.ClientID},
|
|
"client_secret": {config.ClientSecret},
|
|
"refresh_token": {creds.RefreshToken},
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
fmt.Println("[+] Session refreshed.")
|
|
return tr.AccessToken, nil
|
|
}
|
|
|
|
func (a *Authenticator) doTokenRequest(v url.Values) (*models.TokenResponse, error) {
|
|
resp, err := a.HTTPClient.PostForm(config.BaseURL+"/login/oauth2/token", v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != 200 {
|
|
return nil, fmt.Errorf("token request failed: %d", resp.StatusCode)
|
|
}
|
|
|
|
var tr models.TokenResponse
|
|
json.NewDecoder(resp.Body).Decode(&tr)
|
|
return &tr, nil
|
|
}
|
|
|
|
func SaveCredentials(creds *models.Credentials) {
|
|
data, _ := json.MarshalIndent(creds, "", " ")
|
|
os.WriteFile(config.CredsFile, data, 0o644)
|
|
}
|
|
|
|
func LoadCredentials() (*models.Credentials, error) {
|
|
data, err := os.ReadFile(config.CredsFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var creds models.Credentials
|
|
json.Unmarshal(data, &creds)
|
|
return &creds, nil
|
|
}
|