121 lines
4.4 KiB
Go
121 lines
4.4 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.ipao.vip/rogee/creator-hub/internal/creator"
|
|
hub "git.ipao.vip/rogee/creator-hub/internal/environment"
|
|
"github.com/gofiber/fiber/v3"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func registerEnvironmentLoginRoutes(app *fiber.App, store *creator.Store, hubStore *hub.Store) {
|
|
app.Get("/api/creator/environments", func(c fiber.Ctx) error {
|
|
items, err := hubStore.ListPendingEnvironments(c.Context())
|
|
if err != nil {
|
|
return hubError(c, err)
|
|
}
|
|
return c.JSON(items)
|
|
})
|
|
app.Post("/api/creator/environments", func(c fiber.Ctx) error {
|
|
var input struct {
|
|
Gateway string `json:"gateway"`
|
|
Fingerprint hub.Fingerprint `json:"fingerprint"`
|
|
}
|
|
if err := decodePhaseA(c, &input); err != nil {
|
|
return phaseAError(c, err)
|
|
}
|
|
env, err := hubStore.CreateStandaloneEnv(c.Context(), input.Gateway, input.Fingerprint)
|
|
if err != nil {
|
|
logrus.WithError(err).WithFields(logrus.Fields{"event_type": "login_environment_create_failed", "gateway": input.Gateway}).Error("browser environment creation failed")
|
|
return hubError(c, err)
|
|
}
|
|
logrus.WithFields(logrus.Fields{"event_type": "login_environment_created", "alias": env.Alias, "gateway": env.Gateway}).Info("browser environment created without platform account")
|
|
return c.Status(fiber.StatusCreated).JSON(env)
|
|
})
|
|
app.Post("/api/creator/environments/:alias/verify", func(c fiber.Ctx) error {
|
|
result, err := verifyLoginEnvironment(c.Context(), store, hubStore, c.Params("alias"))
|
|
if err != nil {
|
|
return creatorError(c, err)
|
|
}
|
|
return c.JSON(result)
|
|
})
|
|
app.Post("/api/creator/environments/:alias/login-qr", func(c fiber.Ctx) error {
|
|
alias := c.Params("alias")
|
|
unlock, err := hubStore.LockResources(c.Context(), []string{alias}, nil)
|
|
if err != nil {
|
|
return hubError(c, err)
|
|
}
|
|
defer unlock()
|
|
env, err := hubStore.GetEnvironmentContext(c.Context(), alias)
|
|
if err != nil {
|
|
return hubError(c, err)
|
|
}
|
|
if err := startCreatorEnvironment(c.Context(), hubStore, env); err != nil {
|
|
return hubError(c, err)
|
|
}
|
|
env, err = hubStore.GetEnvironmentContext(c.Context(), alias)
|
|
if err != nil {
|
|
return hubError(c, err)
|
|
}
|
|
gateway, err := hubStore.GetGateway(c.Context(), env.Gateway)
|
|
if err != nil {
|
|
return hubError(c, err)
|
|
}
|
|
qr, err := (douyinGatewayBrowser{gateway: gateway, environment: env}).LoginQR(c.Context())
|
|
if err != nil {
|
|
return creatorError(c, fmt.Errorf("%w: capture login QR: %v", creator.ErrUnavailable, err))
|
|
}
|
|
return c.JSON(map[string]any{"status": "manual_login", "content_type": qr.ContentType, "image_base64": qr.BodyBase64, "qr_detected": qr.QRDetected, "expires_at": time.Now().UTC().Add(creatorLoginQRLifetime).Format(time.RFC3339)})
|
|
})
|
|
}
|
|
|
|
func verifyLoginEnvironment(ctx context.Context, store *creator.Store, hubStore *hub.Store, alias string) (creator.LoginResult, error) {
|
|
unlock, err := hubStore.LockResources(ctx, []string{alias}, nil)
|
|
if err != nil {
|
|
return creator.LoginResult{}, err
|
|
}
|
|
defer unlock()
|
|
env, err := hubStore.GetEnvironmentContext(ctx, alias)
|
|
if err != nil {
|
|
return creator.LoginResult{}, err
|
|
}
|
|
if err := startCreatorEnvironment(ctx, hubStore, env); err != nil {
|
|
return creator.LoginResult{}, err
|
|
}
|
|
env, err = hubStore.GetEnvironmentContext(ctx, alias)
|
|
if err != nil {
|
|
return creator.LoginResult{}, err
|
|
}
|
|
expected := ""
|
|
if env.AccountID != "" {
|
|
p, err := store.GetAccountProfile(ctx, env.AccountID)
|
|
if err != nil {
|
|
return creator.LoginResult{}, err
|
|
}
|
|
expected = p.PlatformAccountKey
|
|
}
|
|
gateway, err := hubStore.GetGateway(ctx, env.Gateway)
|
|
if err != nil {
|
|
return creator.LoginResult{}, err
|
|
}
|
|
identity, err := (creatorGatewayBrowser{gateway: gateway, environment: env}).IdentityProfile(ctx, expected)
|
|
if errors.Is(err, errCreatorLoginPending) {
|
|
return creator.LoginResult{Status: "manual_login", Reason: "awaiting_login", CheckedAt: time.Now().UTC()}, nil
|
|
}
|
|
if err != nil {
|
|
return creator.LoginResult{}, fmt.Errorf("%w: browser identity: %v", creator.ErrConflict, err)
|
|
}
|
|
result, err := store.RecordVerifiedEnvironmentLogin(ctx, alias, identity)
|
|
entry := logrus.WithFields(logrus.Fields{"event_type": "environment_login_verified", "alias": alias, "uid": identity.UID, "account_id": result.AccountID})
|
|
if err != nil {
|
|
entry.WithError(err).Warn("browser account binding rejected")
|
|
return creator.LoginResult{}, err
|
|
}
|
|
entry.Info("platform account bound and profile synchronized")
|
|
return result, nil
|
|
}
|