chatdesk-ui/auth_v2.169.0/internal/api/provider/provider.go

129 lines
4.5 KiB
Go

package provider
import (
"bytes"
"context"
"encoding/json"
"io"
"log"
"net/http"
"os"
"time"
"github.com/supabase/auth/internal/utilities"
"golang.org/x/oauth2"
)
var defaultTimeout time.Duration = time.Second * 10
func init() {
timeoutStr := os.Getenv("GOTRUE_INTERNAL_HTTP_TIMEOUT")
if timeoutStr != "" {
if timeout, err := time.ParseDuration(timeoutStr); err != nil {
log.Fatalf("error loading GOTRUE_INTERNAL_HTTP_TIMEOUT: %v", err.Error())
} else if timeout != 0 {
defaultTimeout = timeout
}
}
}
type Claims struct {
// Reserved claims
Issuer string `json:"iss,omitempty" structs:"iss,omitempty"`
Subject string `json:"sub,omitempty" structs:"sub,omitempty"`
Aud string `json:"aud,omitempty" structs:"aud,omitempty"`
Iat float64 `json:"iat,omitempty" structs:"iat,omitempty"`
Exp float64 `json:"exp,omitempty" structs:"exp,omitempty"`
// Default profile claims
Name string `json:"name,omitempty" structs:"name,omitempty"`
FamilyName string `json:"family_name,omitempty" structs:"family_name,omitempty"`
GivenName string `json:"given_name,omitempty" structs:"given_name,omitempty"`
MiddleName string `json:"middle_name,omitempty" structs:"middle_name,omitempty"`
NickName string `json:"nickname,omitempty" structs:"nickname,omitempty"`
PreferredUsername string `json:"preferred_username,omitempty" structs:"preferred_username,omitempty"`
Profile string `json:"profile,omitempty" structs:"profile,omitempty"`
Picture string `json:"picture,omitempty" structs:"picture,omitempty"`
Website string `json:"website,omitempty" structs:"website,omitempty"`
Gender string `json:"gender,omitempty" structs:"gender,omitempty"`
Birthdate string `json:"birthdate,omitempty" structs:"birthdate,omitempty"`
ZoneInfo string `json:"zoneinfo,omitempty" structs:"zoneinfo,omitempty"`
Locale string `json:"locale,omitempty" structs:"locale,omitempty"`
UpdatedAt string `json:"updated_at,omitempty" structs:"updated_at,omitempty"`
Email string `json:"email,omitempty" structs:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty" structs:"email_verified"`
Phone string `json:"phone,omitempty" structs:"phone,omitempty"`
PhoneVerified bool `json:"phone_verified,omitempty" structs:"phone_verified"`
// Custom profile claims that are provider specific
CustomClaims map[string]interface{} `json:"custom_claims,omitempty" structs:"custom_claims,omitempty"`
// TODO: Deprecate in next major release
FullName string `json:"full_name,omitempty" structs:"full_name,omitempty"`
AvatarURL string `json:"avatar_url,omitempty" structs:"avatar_url,omitempty"`
Slug string `json:"slug,omitempty" structs:"slug,omitempty"`
ProviderId string `json:"provider_id,omitempty" structs:"provider_id,omitempty"`
UserNameKey string `json:"user_name,omitempty" structs:"user_name,omitempty"`
}
// Email is a struct that provides information on whether an email is verified or is the primary email address
type Email struct {
Email string
Verified bool
Primary bool
}
// UserProvidedData is a struct that contains the user's data returned from the oauth provider
type UserProvidedData struct {
Emails []Email
Metadata *Claims
}
// Provider is an interface for interacting with external account providers
type Provider interface {
AuthCodeURL(string, ...oauth2.AuthCodeOption) string
}
// OAuthProvider specifies additional methods needed for providers using OAuth
type OAuthProvider interface {
AuthCodeURL(string, ...oauth2.AuthCodeOption) string
GetUserData(context.Context, *oauth2.Token) (*UserProvidedData, error)
GetOAuthToken(string) (*oauth2.Token, error)
}
func chooseHost(base, defaultHost string) string {
if base == "" {
return "https://" + defaultHost
}
baseLen := len(base)
if base[baseLen-1] == '/' {
return base[:baseLen-1]
}
return base
}
func makeRequest(ctx context.Context, tok *oauth2.Token, g *oauth2.Config, url string, dst interface{}) error {
client := g.Client(ctx, tok)
client.Timeout = defaultTimeout
res, err := client.Get(url)
if err != nil {
return err
}
defer utilities.SafeClose(res.Body)
bodyBytes, _ := io.ReadAll(res.Body)
res.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusMultipleChoices {
return httpError(res.StatusCode, string(bodyBytes))
}
if err := json.NewDecoder(res.Body).Decode(dst); err != nil {
return err
}
return nil
}