201 lines
5.9 KiB
Go
201 lines
5.9 KiB
Go
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
func (h *handler) pauseUser(c *gin.Context) {
|
|
if _, ok := h.requireAdminPermission(c, permissionAdminUsersPause); !ok {
|
|
return
|
|
}
|
|
|
|
userID := c.Param("userId")
|
|
user, err := h.store.GetUserByID(c.Request.Context(), userID)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "user_lookup_failed", "failed to find user")
|
|
return
|
|
}
|
|
if h.isRootAccount(user) {
|
|
respondError(c, http.StatusForbidden, "root_protected", "root account cannot be paused")
|
|
return
|
|
}
|
|
|
|
user.Active = false
|
|
if err := h.store.UpdateUser(c.Request.Context(), user); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "update_failed", "failed to pause user")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "user paused"})
|
|
}
|
|
|
|
func (h *handler) resumeUser(c *gin.Context) {
|
|
if _, ok := h.requireAdminPermission(c, permissionAdminUsersResume); !ok {
|
|
return
|
|
}
|
|
|
|
userID := c.Param("userId")
|
|
user, err := h.store.GetUserByID(c.Request.Context(), userID)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "user_lookup_failed", "failed to find user")
|
|
return
|
|
}
|
|
if h.isRootAccount(user) {
|
|
respondError(c, http.StatusForbidden, "root_protected", "root account is always active")
|
|
return
|
|
}
|
|
|
|
user.Active = true
|
|
if err := h.store.UpdateUser(c.Request.Context(), user); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "update_failed", "failed to resume user")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "user resumed"})
|
|
}
|
|
|
|
func (h *handler) deleteUser(c *gin.Context) {
|
|
if _, ok := h.requireAdminPermission(c, permissionAdminUsersDelete); !ok {
|
|
return
|
|
}
|
|
|
|
userID := c.Param("userId")
|
|
user, err := h.store.GetUserByID(c.Request.Context(), userID)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "user_lookup_failed", "failed to find user")
|
|
return
|
|
}
|
|
if h.isRootAccount(user) {
|
|
respondError(c, http.StatusForbidden, "root_protected", "root account cannot be deleted")
|
|
return
|
|
}
|
|
if err := h.store.DeleteUser(c.Request.Context(), userID); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "delete_failed", "failed to delete user")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "user deleted"})
|
|
}
|
|
|
|
func (h *handler) renewProxyUUID(c *gin.Context) {
|
|
if _, ok := h.requireAdminPermission(c, permissionAdminUsersRenewUUID); !ok {
|
|
return
|
|
}
|
|
|
|
userID := c.Param("userId")
|
|
var req struct {
|
|
ExpiresInDays int `json:"expires_in_days"`
|
|
ExpiresAt string `json:"expires_at"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
respondError(c, http.StatusBadRequest, "invalid_request", "invalid request payload")
|
|
return
|
|
}
|
|
|
|
user, err := h.store.GetUserByID(c.Request.Context(), userID)
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "user_lookup_failed", "failed to find user")
|
|
return
|
|
}
|
|
if h.isRootAccount(user) {
|
|
respondError(c, http.StatusForbidden, "root_protected", "root account UUID cannot be renewed")
|
|
return
|
|
}
|
|
|
|
// Generate new UUID
|
|
// We use crypto/rand usually, but for simplicity here we assume a helper or just a placeholder
|
|
// Since I don't have a helper, I'll use a simple random string or assume store handles it if empty
|
|
// Actually, ProxyUUID is a string in the Store.
|
|
user.ProxyUUID = "" // Let the store or a helper generate it if we had one.
|
|
// Since I can't easily import a uuid generator here without checking if it's available,
|
|
// I'll just use a placeholder for now or assume the user wants a new one.
|
|
// Wait, schema says it has a default gen_random_uuid().
|
|
|
|
if req.ExpiresAt != "" {
|
|
t, err := time.Parse("2006-01-02", req.ExpiresAt)
|
|
if err != nil {
|
|
respondError(c, http.StatusBadRequest, "invalid_date", "invalid date format, use YYYY-MM-DD")
|
|
return
|
|
}
|
|
expiration := t.UTC()
|
|
user.ProxyUUIDExpiresAt = &expiration
|
|
} else if req.ExpiresInDays > 0 {
|
|
expiration := time.Now().UTC().AddDate(0, 0, req.ExpiresInDays)
|
|
user.ProxyUUIDExpiresAt = &expiration
|
|
} else {
|
|
user.ProxyUUIDExpiresAt = nil
|
|
}
|
|
|
|
// For now, let's just use a simple random hex string if we want to "reset" it manually
|
|
// in the logic before UpdateUser.
|
|
user.ProxyUUID = generateRandomUUID()
|
|
|
|
if err := h.store.UpdateUser(c.Request.Context(), user); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "update_failed", "failed to renew proxy UUID")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "proxy UUID renewed",
|
|
"proxy_uuid": user.ProxyUUID,
|
|
"expires_at": user.ProxyUUIDExpiresAt,
|
|
})
|
|
}
|
|
|
|
func (h *handler) listBlacklist(c *gin.Context) {
|
|
if _, ok := h.requireAdminPermission(c, permissionAdminBlacklistRead); !ok {
|
|
return
|
|
}
|
|
|
|
list, err := h.store.ListBlacklist(c.Request.Context())
|
|
if err != nil {
|
|
respondError(c, http.StatusInternalServerError, "list_failed", "failed to list blacklist")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"blacklist": list})
|
|
}
|
|
|
|
func (h *handler) addToBlacklist(c *gin.Context) {
|
|
if _, ok := h.requireAdminPermission(c, permissionAdminBlacklistWrite); !ok {
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Email string `json:"email"`
|
|
}
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
respondError(c, http.StatusBadRequest, "invalid_request", "invalid request payload")
|
|
return
|
|
}
|
|
|
|
if err := h.store.AddToBlacklist(c.Request.Context(), req.Email); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "add_failed", "failed to add to blacklist")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "email added to blacklist"})
|
|
}
|
|
|
|
func (h *handler) removeFromBlacklist(c *gin.Context) {
|
|
if _, ok := h.requireAdminPermission(c, permissionAdminBlacklistWrite); !ok {
|
|
return
|
|
}
|
|
|
|
email := c.Param("email")
|
|
if err := h.store.RemoveFromBlacklist(c.Request.Context(), email); err != nil {
|
|
respondError(c, http.StatusInternalServerError, "remove_failed", "failed to remove from blacklist")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "email removed from blacklist"})
|
|
}
|
|
|
|
func generateRandomUUID() string {
|
|
return uuid.New().String()
|
|
}
|