Files
NixMsg/internal/app/identity/app.go
T

136 lines
3.4 KiB
Go

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
// Downlink 可选:停用/删除时发 revoked 与群事件;未接线时为 nil。
Downlink port.Downlink
}
// 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
down port.Downlink
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,
down: cfg.Downlink,
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)