fix: 停用删除重置密码发 fatal 并注入 Downlink 发 revoked

This commit is contained in:
Nixevol
2026-09-30 10:55:25 +08:00
parent 479a08ee11
commit 1d6be59652
7 changed files with 396 additions and 36 deletions
+32 -5
View File
@@ -102,6 +102,33 @@ func (h *Handler) kickEndpoint(ctx context.Context, id string) (bool, error) {
return h.kick(ctx, id)
}
func (h *Handler) passwordResetKick(ctx context.Context, id string) (bool, error) {
if h.resetKick != nil {
return h.resetKick(ctx, id)
}
return h.kickEndpoint(ctx, id)
}
func (h *Handler) afterDisableKick(ctx context.Context, id string) {
if h.disableKick != nil {
_, _ = h.disableKick(ctx, id)
return
}
if h.identity == nil {
_, _ = h.kickEndpoint(ctx, id)
}
}
func (h *Handler) afterDeleteKick(ctx context.Context, id string) {
if h.deleteKick != nil {
_, _ = h.deleteKick(ctx, id)
return
}
if h.identity == nil {
_, _ = h.kickEndpoint(ctx, id)
}
}
func (h *Handler) handleEndpointList(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
limit := defaultListLimit
@@ -350,7 +377,7 @@ func (h *Handler) handleEndpointPatch(w http.ResponseWriter, r *http.Request) {
return
}
if !*req.Enabled {
_, _ = h.kickEndpoint(r.Context(), id)
h.afterDisableKick(r.Context(), id)
}
} else if req.Enabled != nil && !*req.Enabled && wasEnabled {
_, _ = h.kickEndpoint(r.Context(), id)
@@ -381,7 +408,7 @@ func (h *Handler) handleEndpointDelete(w http.ResponseWriter, r *http.Request) {
httpx.WriteError(w, http.StatusNotFound, "not_found", "端不存在")
return
}
_, _ = h.kickEndpoint(r.Context(), id)
h.afterDeleteKick(r.Context(), id)
h.audit(actorString(p), "endpoint_delete", id, "ok", ip)
httpx.WriteOK(w, map[string]any{})
}
@@ -416,14 +443,14 @@ func (h *Handler) handleEndpointBatch(w http.ResponseWriter, r *http.Request) {
case "disable":
found, opErr = h.setEndpointEnabled(r.Context(), id, false)
if found && opErr == nil {
_, _ = h.kickEndpoint(r.Context(), id)
h.afterDisableKick(r.Context(), id)
}
case "enable":
found, opErr = h.setEndpointEnabled(r.Context(), id, true)
case "delete":
found, opErr = h.deleteEndpointBasic(r.Context(), id)
if found && opErr == nil {
_, _ = h.kickEndpoint(r.Context(), id)
h.afterDeleteKick(r.Context(), id)
}
}
if opErr != nil {
@@ -512,7 +539,7 @@ func (h *Handler) handleEndpointResetLoginPassword(w http.ResponseWriter, r *htt
httpx.WriteError(w, http.StatusNotFound, "not_found", "端不存在")
return
}
_, _ = h.kickEndpoint(r.Context(), id)
_, _ = h.passwordResetKick(r.Context(), id)
h.audit(actorString(p), "endpoint_reset_login_password", id, "ok", ip)
httpx.WriteOK(w, map[string]any{loginPasswordOnceKey: pw})
}
+42 -30
View File
@@ -41,6 +41,12 @@ type Deps struct {
SecureCookies bool
// KickEndpoint 踢下线钩子(只断开连接);nil 时踢线为 no-op。
KickEndpoint EndpointKickFunc
// PasswordResetKick 重置登录密码后踢线(应发 fatal);nil 时回退 KickEndpoint。
PasswordResetKick EndpointKickFunc
// DisableKick 停用后踢线(应发 fatal(disabled));nil 且已注入 Identity 时不再 Kick。
DisableKick EndpointKickFunc
// DeleteKick 删除后踢线(应发 fatal(deleted));nil 且已注入 Identity 时不再 Kick。
DeleteKick EndpointKickFunc
// Identity 端停用/启用/删除级联(I5);nil 时回退为仅改 enabled/删行。
Identity identity.Service
@@ -54,20 +60,23 @@ type Deps struct {
// Handler 是可挂载的管理接口(路由前缀 /api/admin/)。
type Handler struct {
db *store.DB
hash auth.HashPool
tokens auth.APITokens
locks auth.LoginLocks
log *slog.Logger
trusted []*net.IPNet
ttl time.Duration
forceSec bool
kick EndpointKickFunc
identity identity.Service
groups group.Service
cfg config.Config
version string
startedAt time.Time
db *store.DB
hash auth.HashPool
tokens auth.APITokens
locks auth.LoginLocks
log *slog.Logger
trusted []*net.IPNet
ttl time.Duration
forceSec bool
kick EndpointKickFunc
resetKick EndpointKickFunc
disableKick EndpointKickFunc
deleteKick EndpointKickFunc
identity identity.Service
groups group.Service
cfg config.Config
version string
startedAt time.Time
mux *http.ServeMux
@@ -96,22 +105,25 @@ func New(d Deps) *Handler {
ver = "dev"
}
h := &Handler{
db: d.DB,
hash: d.Hash,
tokens: d.Tokens,
locks: d.Locks,
log: d.Logger,
trusted: d.TrustedProxies,
ttl: ttl,
forceSec: d.SecureCookies,
kick: d.KickEndpoint,
identity: d.Identity,
groups: d.Groups,
cfg: cfg,
version: ver,
startedAt: time.Now(),
mux: http.NewServeMux(),
lastUsed: make(map[string]time.Time),
db: d.DB,
hash: d.Hash,
tokens: d.Tokens,
locks: d.Locks,
log: d.Logger,
trusted: d.TrustedProxies,
ttl: ttl,
forceSec: d.SecureCookies,
kick: d.KickEndpoint,
resetKick: d.PasswordResetKick,
disableKick: d.DisableKick,
deleteKick: d.DeleteKick,
identity: d.Identity,
groups: d.Groups,
cfg: cfg,
version: ver,
startedAt: time.Now(),
mux: http.NewServeMux(),
lastUsed: make(map[string]time.Time),
}
h.routes()
return h