aboutsummaryrefslogtreecommitdiffhomepage
path: root/backend/auth/auth.go
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2024-08-17 18:59:55 +0900
committernsfisis <nsfisis@gmail.com>2024-08-17 18:59:55 +0900
commitf926ef682de637b717d3b0cc0eaee43c59e83c95 (patch)
treea6cc6852ecdfe5643d336b77e9956fe6383d53ef /backend/auth/auth.go
parent29721ab9971c401d5fb5d2a2cfd730b156a8e195 (diff)
downloadphperkaigi-2025-albatross-f926ef682de637b717d3b0cc0eaee43c59e83c95.tar.gz
phperkaigi-2025-albatross-f926ef682de637b717d3b0cc0eaee43c59e83c95.tar.zst
phperkaigi-2025-albatross-f926ef682de637b717d3b0cc0eaee43c59e83c95.zip
feat(backend): allow login/signup with email address
Diffstat (limited to 'backend/auth/auth.go')
-rw-r--r--backend/auth/auth.go74
1 files changed, 40 insertions, 34 deletions
diff --git a/backend/auth/auth.go b/backend/auth/auth.go
index 4224675..0e55d8d 100644
--- a/backend/auth/auth.go
+++ b/backend/auth/auth.go
@@ -3,8 +3,6 @@ package auth
import (
"context"
"errors"
- "fmt"
- "strings"
"time"
"github.com/jackc/pgx/v5"
@@ -18,7 +16,6 @@ var (
ErrInvalidRegistrationToken = errors.New("invalid registration token")
ErrNoRegistrationToken = errors.New("no registration token")
ErrForteeLoginTimeout = errors.New("fortee login timeout")
- ErrForteeEmailUsed = errors.New("fortee email used")
)
const (
@@ -33,17 +30,12 @@ func Login(
registrationToken *string,
) (int, error) {
userAuth, err := queries.GetUserAuthByUsername(ctx, username)
- if err != nil {
- if errors.Is(err, pgx.ErrNoRows) {
- err := signup(ctx, queries, username, password, registrationToken)
- if err != nil {
- return 0, err
- }
- return Login(ctx, queries, username, password, nil)
- }
+ if err != nil && !errors.Is(err, pgx.ErrNoRows) {
return 0, err
}
+
if userAuth.AuthType == "password" {
+ // Authenticate with password.
passwordHash := userAuth.PasswordHash
if passwordHash == nil {
panic("inconsistant data")
@@ -53,41 +45,60 @@ func Login(
return 0, err
}
return int(userAuth.UserID), nil
- } else if userAuth.AuthType == "fortee" {
- if err := verifyForteeAccount(ctx, username, password); err != nil {
- return 0, err
+ }
+
+ // Authenticate with fortee.
+ return verifyForteeAccountOrSignup(ctx, queries, username, password, registrationToken)
+}
+
+func verifyForteeAccountOrSignup(
+ ctx context.Context,
+ queries *db.Queries,
+ username string,
+ password string,
+ registrationToken *string,
+) (int, error) {
+ canonicalizedUsername, err := verifyForteeAccount(ctx, username, password)
+ if err != nil {
+ return 0, err
+ }
+ userID, err := queries.GetUserIDByUsername(ctx, canonicalizedUsername)
+ if err != nil {
+ if errors.Is(err, pgx.ErrNoRows) {
+ return signup(
+ ctx,
+ queries,
+ canonicalizedUsername,
+ registrationToken,
+ )
}
- return int(userAuth.UserID), nil
+ return 0, err
}
- panic(fmt.Sprintf("unexpected auth type: %s", userAuth.AuthType))
+ return int(userID), nil
}
func signup(
ctx context.Context,
queries *db.Queries,
username string,
- password string,
registrationToken *string,
-) error {
+) (int, error) {
if err := verifyRegistrationToken(ctx, queries, registrationToken); err != nil {
- return err
- }
- if err := verifyForteeAccount(ctx, username, password); err != nil {
- return err
+ return 0, err
}
// TODO: transaction
userID, err := queries.CreateUser(ctx, username)
if err != nil {
- return err
+ return 0, err
}
if err := queries.CreateUserAuth(ctx, db.CreateUserAuthParams{
UserID: userID,
AuthType: "fortee",
}); err != nil {
- return err
+ return 0, err
}
- return nil
+ return int(userID), nil
}
func verifyRegistrationToken(ctx context.Context, queries *db.Queries, registrationToken *string) error {
@@ -104,18 +115,13 @@ func verifyRegistrationToken(ctx context.Context, queries *db.Queries, registrat
return nil
}
-func verifyForteeAccount(ctx context.Context, username string, password string) error {
- // fortee API allows login with email address, but this system disallows it.
- if strings.Contains(username, "@") {
- return ErrForteeEmailUsed
- }
-
+func verifyForteeAccount(ctx context.Context, username string, password string) (string, error) {
ctx, cancel := context.WithTimeout(ctx, forteeAPITimeout)
defer cancel()
- err := fortee.LoginFortee(ctx, username, password)
+ canonicalizedUsername, err := fortee.LoginFortee(ctx, username, password)
if errors.Is(err, context.DeadlineExceeded) {
- return ErrForteeLoginTimeout
+ return "", ErrForteeLoginTimeout
}
- return err
+ return canonicalizedUsername, err
}