65 lines
1.5 KiB
Go
65 lines
1.5 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"errors"
|
|
|
|
"codeberg.org/nextgo/dbots/internal/db"
|
|
"codeberg.org/nextgo/dbots/internal/discord"
|
|
"github.com/jackc/pgx/v5"
|
|
)
|
|
|
|
// todo: api keysssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
|
|
// or sessions????????????
|
|
type Service struct {
|
|
q *db.Queries
|
|
client *discord.Client
|
|
}
|
|
|
|
func NewService(q *db.Queries, client *discord.Client) *Service {
|
|
return &Service{q: q, client: client}
|
|
}
|
|
|
|
// GenerateState produces a random OAuth state parameter.
|
|
func GenerateState() (string, error) {
|
|
b := make([]byte, 16)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", err
|
|
}
|
|
return base64.URLEncoding.EncodeToString(b), nil
|
|
}
|
|
|
|
// Callback handles the OAuth callback: exchanges the code, fetches the user,
|
|
// and upserts them in the database. Returns the local db.User.
|
|
func (s *Service) Callback(ctx context.Context, code string) (*db.User, error) {
|
|
token, err := s.client.ExchangeCode(ctx, code)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dUser, err := s.client.GetCurrentUser(ctx, token.AccessToken)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
user, err := s.q.UpdateUser(ctx, db.UpdateUserParams{
|
|
ID: dUser.ID,
|
|
Username: &dUser.Username,
|
|
})
|
|
if err != nil {
|
|
if errors.Is(err, pgx.ErrNoRows) {
|
|
user, err = s.q.CreateUser(ctx, db.CreateUserParams{
|
|
ID: dUser.ID,
|
|
Username: dUser.Username,
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
return user, nil
|
|
}
|