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")
|
apiGroup := r.Group("/api")
|
||||||
controller.NewWebauthnController(apiGroup, jwtAuthMiddleware, middleware.NewRateLimitMiddleware(), webauthnService)
|
controller.NewWebauthnController(apiGroup, jwtAuthMiddleware, middleware.NewRateLimitMiddleware(), webauthnService)
|
||||||
controller.NewOidcController(apiGroup, jwtAuthMiddleware, fileSizeLimitMiddleware, oidcService, jwtService)
|
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.NewAppConfigController(apiGroup, jwtAuthMiddleware, appConfigService)
|
||||||
controller.NewAuditLogController(apiGroup, auditLogService, jwtAuthMiddleware)
|
controller.NewAuditLogController(apiGroup, auditLogService, jwtAuthMiddleware)
|
||||||
controller.NewUserGroupController(apiGroup, jwtAuthMiddleware, userGroupService)
|
controller.NewUserGroupController(apiGroup, jwtAuthMiddleware, userGroupService)
|
||||||
|
|||||||
@@ -104,7 +104,6 @@ type ClientIdOrSecretNotProvidedError struct{}
|
|||||||
func (e *ClientIdOrSecretNotProvidedError) Error() string {
|
func (e *ClientIdOrSecretNotProvidedError) Error() string {
|
||||||
return "Client id and secret not provided"
|
return "Client id and secret not provided"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ClientIdOrSecretNotProvidedError) HttpStatusCode() int { return http.StatusBadRequest }
|
func (e *ClientIdOrSecretNotProvidedError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type WrongFileTypeError struct {
|
type WrongFileTypeError struct {
|
||||||
@@ -114,7 +113,6 @@ type WrongFileTypeError struct {
|
|||||||
func (e *WrongFileTypeError) Error() string {
|
func (e *WrongFileTypeError) Error() string {
|
||||||
return fmt.Sprintf("File must be of type %s", e.ExpectedFileType)
|
return fmt.Sprintf("File must be of type %s", e.ExpectedFileType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *WrongFileTypeError) HttpStatusCode() int { return http.StatusBadRequest }
|
func (e *WrongFileTypeError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type MissingSessionIdError struct{}
|
type MissingSessionIdError struct{}
|
||||||
@@ -122,7 +120,6 @@ type MissingSessionIdError struct{}
|
|||||||
func (e *MissingSessionIdError) Error() string {
|
func (e *MissingSessionIdError) Error() string {
|
||||||
return "Missing session id"
|
return "Missing session id"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *MissingSessionIdError) HttpStatusCode() int { return http.StatusBadRequest }
|
func (e *MissingSessionIdError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type ReservedClaimError struct {
|
type ReservedClaimError struct {
|
||||||
@@ -132,7 +129,6 @@ type ReservedClaimError struct {
|
|||||||
func (e *ReservedClaimError) Error() string {
|
func (e *ReservedClaimError) Error() string {
|
||||||
return fmt.Sprintf("Claim %s is reserved and can't be used", e.Key)
|
return fmt.Sprintf("Claim %s is reserved and can't be used", e.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ReservedClaimError) HttpStatusCode() int { return http.StatusBadRequest }
|
func (e *ReservedClaimError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
type DuplicateClaimError struct {
|
type DuplicateClaimError struct {
|
||||||
@@ -142,5 +138,11 @@ type DuplicateClaimError struct {
|
|||||||
func (e *DuplicateClaimError) Error() string {
|
func (e *DuplicateClaimError) Error() string {
|
||||||
return fmt.Sprintf("Claim %s is already defined", e.Key)
|
return fmt.Sprintf("Claim %s is already defined", e.Key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DuplicateClaimError) HttpStatusCode() int { return http.StatusBadRequest }
|
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 (
|
import (
|
||||||
"github.com/gin-gonic/gin"
|
"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/dto"
|
||||||
"github.com/stonith404/pocket-id/backend/internal/middleware"
|
"github.com/stonith404/pocket-id/backend/internal/middleware"
|
||||||
"github.com/stonith404/pocket-id/backend/internal/service"
|
"github.com/stonith404/pocket-id/backend/internal/service"
|
||||||
@@ -11,9 +12,10 @@ import (
|
|||||||
"time"
|
"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{
|
uc := UserController{
|
||||||
UserService: userService,
|
UserService: userService,
|
||||||
|
AppConfigService: appConfigService,
|
||||||
}
|
}
|
||||||
|
|
||||||
group.GET("/users", jwtAuthMiddleware.Add(true), uc.listUsersHandler)
|
group.GET("/users", jwtAuthMiddleware.Add(true), uc.listUsersHandler)
|
||||||
@@ -31,6 +33,7 @@ func NewUserController(group *gin.RouterGroup, jwtAuthMiddleware *middleware.Jwt
|
|||||||
|
|
||||||
type UserController struct {
|
type UserController struct {
|
||||||
UserService *service.UserService
|
UserService *service.UserService
|
||||||
|
AppConfigService *service.AppConfigService
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uc *UserController) listUsersHandler(c *gin.Context) {
|
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) {
|
func (uc *UserController) updateCurrentUserHandler(c *gin.Context) {
|
||||||
|
if uc.AppConfigService.DbConfig.AllowOwnAccountEdit.Value != "true" {
|
||||||
|
c.Error(&common.AccountEditNotAllowedError{})
|
||||||
|
return
|
||||||
|
}
|
||||||
uc.updateUser(c, true)
|
uc.updateUser(c, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type AppConfigUpdateDto struct {
|
|||||||
AppName string `json:"appName" binding:"required,min=1,max=30"`
|
AppName string `json:"appName" binding:"required,min=1,max=30"`
|
||||||
SessionDuration string `json:"sessionDuration" binding:"required"`
|
SessionDuration string `json:"sessionDuration" binding:"required"`
|
||||||
EmailsVerified string `json:"emailsVerified" binding:"required"`
|
EmailsVerified string `json:"emailsVerified" binding:"required"`
|
||||||
|
AllowOwnAccountEdit string `json:"allowOwnAccountEdit" binding:"required"`
|
||||||
EmailEnabled string `json:"emailEnabled" binding:"required"`
|
EmailEnabled string `json:"emailEnabled" binding:"required"`
|
||||||
SmtHost string `json:"smtpHost"`
|
SmtHost string `json:"smtpHost"`
|
||||||
SmtpPort string `json:"smtpPort"`
|
SmtpPort string `json:"smtpPort"`
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ type AppConfigVariable struct {
|
|||||||
|
|
||||||
type AppConfig struct {
|
type AppConfig struct {
|
||||||
AppName AppConfigVariable
|
AppName AppConfigVariable
|
||||||
|
SessionDuration AppConfigVariable
|
||||||
|
EmailsVerified AppConfigVariable
|
||||||
|
AllowOwnAccountEdit AppConfigVariable
|
||||||
|
|
||||||
BackgroundImageType AppConfigVariable
|
BackgroundImageType AppConfigVariable
|
||||||
LogoLightImageType AppConfigVariable
|
LogoLightImageType AppConfigVariable
|
||||||
LogoDarkImageType AppConfigVariable
|
LogoDarkImageType AppConfigVariable
|
||||||
SessionDuration AppConfigVariable
|
|
||||||
EmailsVerified AppConfigVariable
|
|
||||||
|
|
||||||
EmailEnabled AppConfigVariable
|
EmailEnabled AppConfigVariable
|
||||||
SmtpHost AppConfigVariable
|
SmtpHost AppConfigVariable
|
||||||
|
|||||||
@@ -46,6 +46,12 @@ var defaultDbConfig = model.AppConfig{
|
|||||||
Type: "bool",
|
Type: "bool",
|
||||||
DefaultValue: "false",
|
DefaultValue: "false",
|
||||||
},
|
},
|
||||||
|
AllowOwnAccountEdit: model.AppConfigVariable{
|
||||||
|
Key: "allowOwnAccountEdit",
|
||||||
|
Type: "bool",
|
||||||
|
IsPublic: true,
|
||||||
|
DefaultValue: "true",
|
||||||
|
},
|
||||||
BackgroundImageType: model.AppConfigVariable{
|
BackgroundImageType: model.AppConfigVariable{
|
||||||
Key: "backgroundImageType",
|
Key: "backgroundImageType",
|
||||||
Type: "string",
|
Type: "string",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
export type AppConfig = {
|
export type AppConfig = {
|
||||||
appName: string;
|
appName: string;
|
||||||
|
allowOwnAccountEdit: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AllAppConfig = AppConfig & {
|
export type AllAppConfig = AppConfig & {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import * as Card from '$lib/components/ui/card';
|
import * as Card from '$lib/components/ui/card';
|
||||||
import UserService from '$lib/services/user-service';
|
import UserService from '$lib/services/user-service';
|
||||||
import WebAuthnService from '$lib/services/webauthn-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 { Passkey } from '$lib/types/passkey.type';
|
||||||
import type { UserCreate } from '$lib/types/user.type';
|
import type { UserCreate } from '$lib/types/user.type';
|
||||||
import { axiosErrorToast, getWebauthnErrorMessage } from '$lib/utils/error-util';
|
import { axiosErrorToast, getWebauthnErrorMessage } from '$lib/utils/error-util';
|
||||||
@@ -51,6 +52,7 @@
|
|||||||
<title>Account Settings</title>
|
<title>Account Settings</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
|
{#if $appConfigStore.allowOwnAccountEdit}
|
||||||
<Card.Root>
|
<Card.Root>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
<Card.Title>Account Details</Card.Title>
|
<Card.Title>Account Details</Card.Title>
|
||||||
@@ -59,6 +61,7 @@
|
|||||||
<AccountForm {account} callback={updateAccount} />
|
<AccountForm {account} callback={updateAccount} />
|
||||||
</Card.Content>
|
</Card.Content>
|
||||||
</Card.Root>
|
</Card.Root>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<Card.Root>
|
<Card.Root>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
const updatedAppConfig = {
|
const updatedAppConfig = {
|
||||||
appName: appConfig.appName,
|
appName: appConfig.appName,
|
||||||
sessionDuration: appConfig.sessionDuration,
|
sessionDuration: appConfig.sessionDuration,
|
||||||
emailsVerified: appConfig.emailsVerified
|
emailsVerified: appConfig.emailsVerified,
|
||||||
|
allowOwnAccountEdit: appConfig.allowOwnAccountEdit
|
||||||
};
|
};
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
appName: z.string().min(2).max(30),
|
appName: z.string().min(2).max(30),
|
||||||
sessionDuration: z.number().min(1).max(43200),
|
sessionDuration: z.number().min(1).max(43200),
|
||||||
emailsVerified: z.boolean()
|
emailsVerified: z.boolean(),
|
||||||
|
allowOwnAccountEdit: z.boolean()
|
||||||
});
|
});
|
||||||
|
|
||||||
const { inputs, ...form } = createForm<typeof formSchema>(formSchema, updatedAppConfig);
|
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."
|
description="The duration of a session in minutes before the user has to sign in again."
|
||||||
bind:input={$inputs.sessionDuration}
|
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">
|
<div class="items-top mt-5 flex space-x-2">
|
||||||
<Checkbox id="admin-privileges" bind:checked={$inputs.emailsVerified.value} />
|
<Checkbox id="admin-privileges" bind:checked={$inputs.emailsVerified.value} />
|
||||||
<div class="grid gap-1.5 leading-none">
|
<div class="grid gap-1.5 leading-none">
|
||||||
|
|||||||
Reference in New Issue
Block a user