dbots/services/auth/auth.go
2026-04-19 01:40:26 +02:00

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
}