feat: add option to disable self-account editing

This commit is contained in:
Elias Schneider
2024-10-28 18:45:27 +01:00
parent 7bfc3f43a5
commit 8304065652
9 changed files with 65 additions and 30 deletions

View File

@@ -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)

View File

@@ -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 }

View File

@@ -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,
AppConfigService: appConfigService,
}
group.GET("/users", jwtAuthMiddleware.Add(true), uc.listUsersHandler)
@@ -31,6 +33,7 @@ func NewUserController(group *gin.RouterGroup, jwtAuthMiddleware *middleware.Jwt
type UserController struct {
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)
}

View File

@@ -15,6 +15,7 @@ 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"`
AllowOwnAccountEdit string `json:"allowOwnAccountEdit" binding:"required"`
EmailEnabled string `json:"emailEnabled" binding:"required"`
SmtHost string `json:"smtpHost"`
SmtpPort string `json:"smtpPort"`

View File

@@ -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

View File

@@ -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",

View File

@@ -1,5 +1,6 @@
export type AppConfig = {
appName: string;
allowOwnAccountEdit: boolean;
};
export type AllAppConfig = AppConfig & {

View File

@@ -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,6 +52,7 @@
<title>Account Settings</title>
</svelte:head>
{#if $appConfigStore.allowOwnAccountEdit}
<Card.Root>
<Card.Header>
<Card.Title>Account Details</Card.Title>
@@ -59,6 +61,7 @@
<AccountForm {account} callback={updateAccount} />
</Card.Content>
</Card.Root>
{/if}
<Card.Root>
<Card.Header>

View File

@@ -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">