mirror of
https://github.com/nikdoof/pocket-id.git
synced 2025-12-14 07:12:19 +00:00
feat: add option to disable self-account editing
This commit is contained in:
@@ -57,7 +57,7 @@ func initRouter(db *gorm.DB, appConfigService *service.AppConfigService) {
|
||||
apiGroup := r.Group("/api")
|
||||
controller.NewWebauthnController(apiGroup, jwtAuthMiddleware, middleware.NewRateLimitMiddleware(), webauthnService)
|
||||
controller.NewOidcController(apiGroup, jwtAuthMiddleware, fileSizeLimitMiddleware, oidcService, jwtService)
|
||||
controller.NewUserController(apiGroup, jwtAuthMiddleware, middleware.NewRateLimitMiddleware(), userService)
|
||||
controller.NewUserController(apiGroup, jwtAuthMiddleware, middleware.NewRateLimitMiddleware(), userService, appConfigService)
|
||||
controller.NewAppConfigController(apiGroup, jwtAuthMiddleware, appConfigService)
|
||||
controller.NewAuditLogController(apiGroup, auditLogService, jwtAuthMiddleware)
|
||||
controller.NewUserGroupController(apiGroup, jwtAuthMiddleware, userGroupService)
|
||||
|
||||
@@ -104,7 +104,6 @@ type ClientIdOrSecretNotProvidedError struct{}
|
||||
func (e *ClientIdOrSecretNotProvidedError) Error() string {
|
||||
return "Client id and secret not provided"
|
||||
}
|
||||
|
||||
func (e *ClientIdOrSecretNotProvidedError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||
|
||||
type WrongFileTypeError struct {
|
||||
@@ -114,7 +113,6 @@ type WrongFileTypeError struct {
|
||||
func (e *WrongFileTypeError) Error() string {
|
||||
return fmt.Sprintf("File must be of type %s", e.ExpectedFileType)
|
||||
}
|
||||
|
||||
func (e *WrongFileTypeError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||
|
||||
type MissingSessionIdError struct{}
|
||||
@@ -122,7 +120,6 @@ type MissingSessionIdError struct{}
|
||||
func (e *MissingSessionIdError) Error() string {
|
||||
return "Missing session id"
|
||||
}
|
||||
|
||||
func (e *MissingSessionIdError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||
|
||||
type ReservedClaimError struct {
|
||||
@@ -132,7 +129,6 @@ type ReservedClaimError struct {
|
||||
func (e *ReservedClaimError) Error() string {
|
||||
return fmt.Sprintf("Claim %s is reserved and can't be used", e.Key)
|
||||
}
|
||||
|
||||
func (e *ReservedClaimError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||
|
||||
type DuplicateClaimError struct {
|
||||
@@ -142,5 +138,11 @@ type DuplicateClaimError struct {
|
||||
func (e *DuplicateClaimError) Error() string {
|
||||
return fmt.Sprintf("Claim %s is already defined", e.Key)
|
||||
}
|
||||
|
||||
func (e *DuplicateClaimError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||
|
||||
type AccountEditNotAllowedError struct{}
|
||||
|
||||
func (e *AccountEditNotAllowedError) Error() string {
|
||||
return "You are not allowed to edit your account"
|
||||
}
|
||||
func (e *AccountEditNotAllowedError) HttpStatusCode() int { return http.StatusForbidden }
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stonith404/pocket-id/backend/internal/common"
|
||||
"github.com/stonith404/pocket-id/backend/internal/dto"
|
||||
"github.com/stonith404/pocket-id/backend/internal/middleware"
|
||||
"github.com/stonith404/pocket-id/backend/internal/service"
|
||||
@@ -11,9 +12,10 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewUserController(group *gin.RouterGroup, jwtAuthMiddleware *middleware.JwtAuthMiddleware, rateLimitMiddleware *middleware.RateLimitMiddleware, userService *service.UserService) {
|
||||
func NewUserController(group *gin.RouterGroup, jwtAuthMiddleware *middleware.JwtAuthMiddleware, rateLimitMiddleware *middleware.RateLimitMiddleware, userService *service.UserService, appConfigService *service.AppConfigService) {
|
||||
uc := UserController{
|
||||
UserService: userService,
|
||||
UserService: userService,
|
||||
AppConfigService: appConfigService,
|
||||
}
|
||||
|
||||
group.GET("/users", jwtAuthMiddleware.Add(true), uc.listUsersHandler)
|
||||
@@ -30,7 +32,8 @@ func NewUserController(group *gin.RouterGroup, jwtAuthMiddleware *middleware.Jwt
|
||||
}
|
||||
|
||||
type UserController struct {
|
||||
UserService *service.UserService
|
||||
UserService *service.UserService
|
||||
AppConfigService *service.AppConfigService
|
||||
}
|
||||
|
||||
func (uc *UserController) listUsersHandler(c *gin.Context) {
|
||||
@@ -124,6 +127,10 @@ func (uc *UserController) updateUserHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (uc *UserController) updateCurrentUserHandler(c *gin.Context) {
|
||||
if uc.AppConfigService.DbConfig.AllowOwnAccountEdit.Value != "true" {
|
||||
c.Error(&common.AccountEditNotAllowedError{})
|
||||
return
|
||||
}
|
||||
uc.updateUser(c, true)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,14 @@ type AppConfigVariableDto struct {
|
||||
}
|
||||
|
||||
type AppConfigUpdateDto struct {
|
||||
AppName string `json:"appName" binding:"required,min=1,max=30"`
|
||||
SessionDuration string `json:"sessionDuration" binding:"required"`
|
||||
EmailsVerified string `json:"emailsVerified" binding:"required"`
|
||||
EmailEnabled string `json:"emailEnabled" binding:"required"`
|
||||
SmtHost string `json:"smtpHost"`
|
||||
SmtpPort string `json:"smtpPort"`
|
||||
SmtpFrom string `json:"smtpFrom" binding:"omitempty,email"`
|
||||
SmtpUser string `json:"smtpUser"`
|
||||
SmtpPassword string `json:"smtpPassword"`
|
||||
AppName string `json:"appName" binding:"required,min=1,max=30"`
|
||||
SessionDuration string `json:"sessionDuration" binding:"required"`
|
||||
EmailsVerified string `json:"emailsVerified" binding:"required"`
|
||||
AllowOwnAccountEdit string `json:"allowOwnAccountEdit" binding:"required"`
|
||||
EmailEnabled string `json:"emailEnabled" binding:"required"`
|
||||
SmtHost string `json:"smtpHost"`
|
||||
SmtpPort string `json:"smtpPort"`
|
||||
SmtpFrom string `json:"smtpFrom" binding:"omitempty,email"`
|
||||
SmtpUser string `json:"smtpUser"`
|
||||
SmtpPassword string `json:"smtpPassword"`
|
||||
}
|
||||
|
||||
@@ -11,11 +11,13 @@ type AppConfigVariable struct {
|
||||
|
||||
type AppConfig struct {
|
||||
AppName AppConfigVariable
|
||||
SessionDuration AppConfigVariable
|
||||
EmailsVerified AppConfigVariable
|
||||
AllowOwnAccountEdit AppConfigVariable
|
||||
|
||||
BackgroundImageType AppConfigVariable
|
||||
LogoLightImageType AppConfigVariable
|
||||
LogoDarkImageType AppConfigVariable
|
||||
SessionDuration AppConfigVariable
|
||||
EmailsVerified AppConfigVariable
|
||||
|
||||
EmailEnabled AppConfigVariable
|
||||
SmtpHost AppConfigVariable
|
||||
|
||||
@@ -46,6 +46,12 @@ var defaultDbConfig = model.AppConfig{
|
||||
Type: "bool",
|
||||
DefaultValue: "false",
|
||||
},
|
||||
AllowOwnAccountEdit: model.AppConfigVariable{
|
||||
Key: "allowOwnAccountEdit",
|
||||
Type: "bool",
|
||||
IsPublic: true,
|
||||
DefaultValue: "true",
|
||||
},
|
||||
BackgroundImageType: model.AppConfigVariable{
|
||||
Key: "backgroundImageType",
|
||||
Type: "string",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export type AppConfig = {
|
||||
appName: string;
|
||||
allowOwnAccountEdit: boolean;
|
||||
};
|
||||
|
||||
export type AllAppConfig = AppConfig & {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import UserService from '$lib/services/user-service';
|
||||
import WebAuthnService from '$lib/services/webauthn-service';
|
||||
import appConfigStore from '$lib/stores/application-configuration-store';
|
||||
import type { Passkey } from '$lib/types/passkey.type';
|
||||
import type { UserCreate } from '$lib/types/user.type';
|
||||
import { axiosErrorToast, getWebauthnErrorMessage } from '$lib/utils/error-util';
|
||||
@@ -51,14 +52,16 @@
|
||||
<title>Account Settings</title>
|
||||
</svelte:head>
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Account Details</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<AccountForm {account} callback={updateAccount} />
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
{#if $appConfigStore.allowOwnAccountEdit}
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Account Details</Card.Title>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<AccountForm {account} callback={updateAccount} />
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
{/if}
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
|
||||
@@ -21,13 +21,15 @@
|
||||
const updatedAppConfig = {
|
||||
appName: appConfig.appName,
|
||||
sessionDuration: appConfig.sessionDuration,
|
||||
emailsVerified: appConfig.emailsVerified
|
||||
emailsVerified: appConfig.emailsVerified,
|
||||
allowOwnAccountEdit: appConfig.allowOwnAccountEdit
|
||||
};
|
||||
|
||||
const formSchema = z.object({
|
||||
appName: z.string().min(2).max(30),
|
||||
sessionDuration: z.number().min(1).max(43200),
|
||||
emailsVerified: z.boolean()
|
||||
emailsVerified: z.boolean(),
|
||||
allowOwnAccountEdit: z.boolean()
|
||||
});
|
||||
|
||||
const { inputs, ...form } = createForm<typeof formSchema>(formSchema, updatedAppConfig);
|
||||
@@ -49,6 +51,17 @@
|
||||
description="The duration of a session in minutes before the user has to sign in again."
|
||||
bind:input={$inputs.sessionDuration}
|
||||
/>
|
||||
<div class="items-top mt-5 flex space-x-2">
|
||||
<Checkbox id="admin-privileges" bind:checked={$inputs.allowOwnAccountEdit.value} />
|
||||
<div class="grid gap-1.5 leading-none">
|
||||
<Label for="admin-privileges" class="mb-0 text-sm font-medium leading-none">
|
||||
Enable Self-Account Editing
|
||||
</Label>
|
||||
<p class="text-muted-foreground text-[0.8rem]">
|
||||
Whether the user should be able to edit their own account details.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="items-top mt-5 flex space-x-2">
|
||||
<Checkbox id="admin-privileges" bind:checked={$inputs.emailsVerified.value} />
|
||||
<div class="grid gap-1.5 leading-none">
|
||||
|
||||
Reference in New Issue
Block a user