aboutsummaryrefslogtreecommitdiffhomepage
path: root/backend/auth/auth.go
diff options
context:
space:
mode:
Diffstat (limited to 'backend/auth/auth.go')
-rw-r--r--backend/auth/auth.go109
1 files changed, 107 insertions, 2 deletions
diff --git a/backend/auth/auth.go b/backend/auth/auth.go
index 401773f..3a292d9 100644
--- a/backend/auth/auth.go
+++ b/backend/auth/auth.go
@@ -1,17 +1,42 @@
package auth
import (
+ "bytes"
"context"
+ "encoding/json"
+ "errors"
"fmt"
+ "net/http"
+ "net/url"
+ "github.com/jackc/pgx/v5"
"golang.org/x/crypto/bcrypt"
"github.com/nsfisis/iosdc-japan-2024-albatross/backend/db"
)
-func Login(ctx context.Context, queries *db.Queries, username, password string) (int, error) {
+var (
+ ErrInvalidRegistrationToken = errors.New("invalid registration token")
+ ErrNoRegistrationToken = errors.New("no registration token")
+ ErrForteeLoginFailed = errors.New("fortee login failed")
+)
+
+func Login(
+ ctx context.Context,
+ queries *db.Queries,
+ username string,
+ password string,
+ 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)
+ }
return 0, err
}
if userAuth.AuthType == "password" {
@@ -24,6 +49,86 @@ func Login(ctx context.Context, queries *db.Queries, username, password string)
return 0, err
}
return int(userAuth.UserID), nil
+ } else if userAuth.AuthType == "fortee" {
+ if err := verifyForteeAccount(ctx, username, password); err != nil {
+ return 0, err
+ }
+ return int(userAuth.UserID), nil
+ }
+ panic(fmt.Sprintf("unexpected auth type: %s", userAuth.AuthType))
+}
+
+func signup(
+ ctx context.Context,
+ queries *db.Queries,
+ username string,
+ password string,
+ registrationToken *string,
+) error {
+ if err := verifyRegistrationToken(ctx, queries, registrationToken); err != nil {
+ return err
+ }
+ if err := verifyForteeAccount(ctx, username, password); err != nil {
+ return err
+ }
+
+ // TODO: transaction
+ userID, err := queries.CreateUser(ctx, username)
+ if err != nil {
+ return err
+ }
+ if err := queries.CreateUserAuth(ctx, db.CreateUserAuthParams{
+ UserID: userID,
+ AuthType: "fortee",
+ }); err != nil {
+ return err
+ }
+ return nil
+}
+
+func verifyRegistrationToken(ctx context.Context, queries *db.Queries, registrationToken *string) error {
+ if registrationToken == nil {
+ return ErrNoRegistrationToken
+ }
+ exists, err := queries.IsRegistrationTokenValid(ctx, *registrationToken)
+ if err != nil {
+ return err
+ }
+ if !exists {
+ return ErrInvalidRegistrationToken
+ }
+ return nil
+}
+
+func verifyForteeAccount(_ context.Context, username string, password string) error {
+ reqData := url.Values{}
+ reqData.Set("username", username)
+ reqData.Set("password", password)
+ reqBody := reqData.Encode()
+
+ req, err := http.NewRequest("POST", "https://fortee.jp/api/user/login", bytes.NewBufferString(reqBody))
+ if err != nil {
+ return fmt.Errorf("http.NewRequest failed: %w", err)
+ }
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ req.Header.Set("Accept", "application/json")
+
+ client := &http.Client{}
+ res, err := client.Do(req)
+ if err != nil {
+ return fmt.Errorf("client.Do failed: %v", err)
+ }
+ defer res.Body.Close()
+
+ resData := struct {
+ LoggedIn bool `json:"loggedIn"`
+ }{}
+ if err := json.NewDecoder(res.Body).Decode(&resData); err != nil {
+ return fmt.Errorf("json.Decode failed: %v", err)
+ }
+
+ if !resData.LoggedIn {
+ return ErrForteeLoginFailed
}
- return 0, fmt.Errorf("not implemented")
+ return nil
}