Add SSH-managed node registry with connection testing and reauth.

Register hosts under Containers/VMs/Docker with encrypted key storage, and require re-authentication for sensitive account changes.
This commit is contained in:
2026-07-18 16:39:10 +02:00
parent b93b7519ec
commit f4dc8f63d7
31 changed files with 4801 additions and 223 deletions
+33 -13
View File
@@ -66,9 +66,12 @@ type loginRequest struct {
}
type meResponse struct {
UserID string `json:"user_id"`
Username string `json:"username"`
Groups []string `json:"groups"`
UserID string `json:"user_id"`
Username string `json:"username"`
Groups []string `json:"groups"`
TOTPConfirmed bool `json:"totp_confirmed"`
TOTPEnabled bool `json:"totp_enabled"`
Permissions []string `json:"permissions"`
}
// App holds shared API dependencies.
@@ -388,11 +391,7 @@ func (app *App) loginHandler(writer http.ResponseWriter, request *http.Request)
return
}
writeJSON(writer, http.StatusOK, meResponse{
UserID: matched.ID,
Username: matched.Username,
Groups: matched.GroupNames,
})
writeJSON(writer, http.StatusOK, app.buildMeResponse(*matched, settingsPayload))
}
func (app *App) logoutHandler(writer http.ResponseWriter, request *http.Request) {
@@ -408,11 +407,32 @@ func (app *App) meHandler(writer http.ResponseWriter, request *http.Request) {
writeJSON(writer, http.StatusUnauthorized, apiErrorResponse{Error: "not authenticated"})
return
}
writeJSON(writer, http.StatusOK, meResponse{
UserID: user.ID,
Username: user.Username,
Groups: user.GroupNames,
})
settingsPayload, err := loadSettingsOrDefault(app.ConfigDir)
if err != nil {
writeJSON(writer, http.StatusInternalServerError, apiErrorResponse{Error: err.Error()})
return
}
writeJSON(writer, http.StatusOK, app.buildMeResponse(user, settingsPayload))
}
func (app *App) buildMeResponse(user settings.UserCredential, settingsPayload settings.Settings) meResponse {
security := effectiveSecurity(settingsPayload.Security)
groups := user.GroupNames
if groups == nil {
groups = []string{}
}
permissions := permissionList(user, settingsPayload.Groups)
if permissions == nil {
permissions = []string{}
}
return meResponse{
UserID: user.ID,
Username: user.Username,
Groups: groups,
TOTPConfirmed: user.TOTPConfirmed,
TOTPEnabled: security.TotpEnabled,
Permissions: permissions,
}
}
func UserFromContext(ctx context.Context) (settings.UserCredential, bool) {