package identity import ( "context" "encoding/hex" "log/slog" "net/http" "time" "git.asio.asia/nixevol/NixMsg/internal/app/port" "git.asio.asia/nixevol/NixMsg/internal/auth" "git.asio.asia/nixevol/NixMsg/internal/protocol" "git.asio.asia/nixevol/NixMsg/internal/store" ) const ( grantKindPassword = "password" grantKindReply = "reply" ) // Config 是身份服务依赖(注册 + self + 对话密码)。 type Config struct { DB *store.DB Hash auth.HashPool Locks auth.LoginLocks Logger *slog.Logger Now func() time.Time // ClientIP 仅注册 HTTP 用。 ClientIP func(*http.Request) string // Sessions 签发会话令牌;改登录密码必填。 Sessions auth.SessionTokens // MaxScheduleSeconds 限制 self.update 的 default_delay_ms。 MaxScheduleSeconds int64 // ConnControl 可选:logout 后踢线;未接线时为 nil。 ConnControl port.ConnControl } // App 实现 identity.Service(含 I1 注册与 I2 self/对话密码)。 type App struct { handler *RegisterHandler db *store.DB hash auth.HashPool locks auth.LoginLocks sessions auth.SessionTokens maxScheduleSeconds int64 connCtrl port.ConnControl nowFn func() time.Time } // New 构造完整身份服务。 func New(cfg Config) *App { if cfg.Logger == nil { cfg.Logger = slog.Default() } if cfg.Now == nil { cfg.Now = time.Now } if cfg.ClientIP == nil { cfg.ClientIP = clientIPFromRemoteAddr } if cfg.Sessions == nil { cfg.Sessions = auth.NewStubSessionTokens() } if cfg.Locks == nil { cfg.Locks = auth.NewStubLoginLocks() } h := NewRegisterHandler(RegisterConfig{ DB: cfg.DB, Hash: cfg.Hash, Locks: cfg.Locks, Logger: cfg.Logger, Now: cfg.Now, ClientIP: cfg.ClientIP, }) return &App{ handler: h, db: cfg.DB, hash: cfg.Hash, locks: cfg.Locks, sessions: cfg.Sessions, maxScheduleSeconds: cfg.MaxScheduleSeconds, connCtrl: cfg.ConnControl, nowFn: cfg.Now, } } // NewServer 兼容 I1:用注册配置构造 Service(会话令牌用 Stub)。 func NewServer(cfg RegisterConfig) *App { return New(Config{ DB: cfg.DB, Hash: cfg.Hash, Locks: cfg.Locks, Logger: cfg.Logger, Now: cfg.Now, ClientIP: cfg.ClientIP, Sessions: auth.NewStubSessionTokens(), }) } func (a *App) now() time.Time { return a.nowFn() } // Handler 返回可挂载的注册 HTTP 处理器。 func (a *App) Handler() http.Handler { return a.handler } // Register 实现自助注册。 func (a *App) Register(ctx context.Context, req RegisterRequest) (RegisterResult, error) { preq := &protocol.RegisterRequest{ RegistrationCode: req.RegistrationCode, ID: req.ID, LoginPassword: req.LoginPassword, Name: req.Name, TalkPassword: req.TalkPassword, } ip := req.RemoteIP if ip == "" { ip = "0.0.0.0" } result, apiErr := a.handler.register(ctx, preq, ip) if apiErr != nil { return RegisterResult{}, apiErr } return result, nil } func encodeSessionHash(hash []byte) string { return hex.EncodeToString(hash) } var _ Service = (*App)(nil) var _ http.Handler = (*RegisterHandler)(nil)