136 lines
3.4 KiB
Go
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)
|