@byline/admin 2.4.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abilities.js +5 -24
- package/dist/index.js +8 -30
- package/dist/lib/assert-admin-actor.js +13 -74
- package/dist/lib/create-command.js +6 -16
- package/dist/modules/admin-account/commands.js +35 -24
- package/dist/modules/admin-account/components/change-password.d.ts +8 -0
- package/dist/modules/admin-account/components/change-password.js +192 -0
- package/dist/modules/admin-account/components/change-password.module.js +8 -0
- package/dist/modules/admin-account/components/change-password_module.css +27 -0
- package/dist/modules/admin-account/components/container.d.ts +29 -0
- package/dist/modules/admin-account/components/container.js +298 -0
- package/dist/modules/admin-account/components/container.module.js +28 -0
- package/dist/modules/admin-account/components/container_module.css +106 -0
- package/dist/modules/admin-account/components/update.d.ts +8 -0
- package/dist/modules/admin-account/components/update.js +207 -0
- package/dist/modules/admin-account/components/update.module.js +8 -0
- package/dist/modules/admin-account/components/update_module.css +27 -0
- package/dist/modules/admin-account/errors.js +14 -45
- package/dist/modules/admin-account/index.js +4 -34
- package/dist/modules/admin-account/schemas.js +25 -59
- package/dist/modules/admin-account/service.js +56 -61
- package/dist/modules/admin-permissions/abilities.js +6 -24
- package/dist/modules/admin-permissions/commands.js +42 -28
- package/dist/modules/admin-permissions/components/inspector.d.ts +4 -0
- package/dist/modules/admin-permissions/components/inspector.js +284 -0
- package/dist/modules/admin-permissions/components/inspector.module.js +56 -0
- package/dist/modules/admin-permissions/components/inspector_module.css +238 -0
- package/dist/modules/admin-permissions/dto.js +3 -16
- package/dist/modules/admin-permissions/errors.js +14 -27
- package/dist/modules/admin-permissions/index.js +6 -26
- package/dist/modules/admin-permissions/repository.js +1 -8
- package/dist/modules/admin-permissions/schemas.js +33 -70
- package/dist/modules/admin-permissions/service.js +88 -92
- package/dist/modules/admin-roles/abilities.js +8 -30
- package/dist/modules/admin-roles/commands.js +89 -55
- package/dist/modules/admin-roles/components/create.d.ts +7 -0
- package/dist/modules/admin-roles/components/create.js +177 -0
- package/dist/modules/admin-roles/components/create.module.js +8 -0
- package/dist/modules/admin-roles/components/create_module.css +27 -0
- package/dist/modules/admin-roles/components/permissions.d.ts +10 -0
- package/dist/modules/admin-roles/components/permissions.js +303 -0
- package/dist/modules/admin-roles/components/permissions.module.js +44 -0
- package/dist/modules/admin-roles/components/permissions_module.css +192 -0
- package/dist/modules/admin-roles/components/update.d.ts +8 -0
- package/dist/modules/admin-roles/components/update.js +166 -0
- package/dist/modules/admin-roles/components/update.module.js +8 -0
- package/dist/modules/admin-roles/components/update_module.css +27 -0
- package/dist/modules/admin-roles/dto.js +3 -16
- package/dist/modules/admin-roles/errors.js +16 -40
- package/dist/modules/admin-roles/index.js +6 -26
- package/dist/modules/admin-roles/repository.js +1 -8
- package/dist/modules/admin-roles/schemas.js +41 -71
- package/dist/modules/admin-roles/service.js +79 -82
- package/dist/modules/admin-users/abilities.js +9 -38
- package/dist/modules/admin-users/commands.js +92 -50
- package/dist/modules/admin-users/components/create.d.ts +8 -0
- package/dist/modules/admin-users/components/create.js +268 -0
- package/dist/modules/admin-users/components/create.module.js +10 -0
- package/dist/modules/admin-users/components/create_module.css +45 -0
- package/dist/modules/admin-users/components/roles.d.ts +11 -0
- package/dist/modules/admin-users/components/roles.js +148 -0
- package/dist/modules/admin-users/components/roles.module.js +18 -0
- package/dist/modules/admin-users/components/roles_module.css +75 -0
- package/dist/modules/admin-users/components/set-password.d.ts +8 -0
- package/dist/modules/admin-users/components/set-password.js +170 -0
- package/dist/modules/admin-users/components/set-password.module.js +9 -0
- package/dist/modules/admin-users/components/set-password_module.css +31 -0
- package/dist/modules/admin-users/components/update.d.ts +8 -0
- package/dist/modules/admin-users/components/update.js +254 -0
- package/dist/modules/admin-users/components/update.module.js +9 -0
- package/dist/modules/admin-users/components/update_module.css +34 -0
- package/dist/modules/admin-users/dto.js +3 -18
- package/dist/modules/admin-users/errors.js +17 -43
- package/dist/modules/admin-users/index.js +7 -27
- package/dist/modules/admin-users/repository.js +1 -8
- package/dist/modules/admin-users/schemas.js +44 -75
- package/dist/modules/admin-users/seed-super-admin.js +9 -34
- package/dist/modules/admin-users/service.js +76 -91
- package/dist/modules/auth/components/sign-in-form.d.ts +12 -0
- package/dist/modules/auth/components/sign-in-form.js +115 -0
- package/dist/modules/auth/components/sign-in-form.module.js +12 -0
- package/dist/modules/auth/components/sign-in-form_module.css +41 -0
- package/dist/modules/auth/index.js +3 -24
- package/dist/modules/auth/jwt-session-provider.js +179 -149
- package/dist/modules/auth/password.js +11 -53
- package/dist/modules/auth/phc.js +21 -54
- package/dist/modules/auth/refresh-tokens-repository.js +1 -8
- package/dist/modules/auth/resolve-actor.js +6 -28
- package/dist/services/admin-services-context.d.ts +16 -0
- package/dist/services/admin-services-context.js +13 -0
- package/dist/services/admin-services-types.d.ts +129 -0
- package/dist/services/admin-services-types.js +1 -0
- package/dist/store.js +1 -8
- package/dist/vendor/noble-argon2/_blake.js +277 -45
- package/dist/vendor/noble-argon2/_md.js +81 -136
- package/dist/vendor/noble-argon2/_u64.js +65 -67
- package/dist/vendor/noble-argon2/argon2.js +181 -342
- package/dist/vendor/noble-argon2/blake2.js +252 -327
- package/dist/vendor/noble-argon2/utils.js +110 -490
- package/dist/vendor/noble-argon2/utils.js.LICENSE.txt +1 -0
- package/package.json +89 -10
- package/src/abilities.ts +32 -0
- package/src/declarations.d.ts +4 -0
- package/src/index.ts +39 -0
- package/src/lib/assert-admin-actor.ts +90 -0
- package/src/lib/create-command.ts +109 -0
- package/src/modules/admin-account/commands.ts +76 -0
- package/src/modules/admin-account/components/change-password.module.css +40 -0
- package/src/modules/admin-account/components/change-password.tsx +232 -0
- package/src/modules/admin-account/components/container.module.css +158 -0
- package/src/modules/admin-account/components/container.tsx +229 -0
- package/src/modules/admin-account/components/update.module.css +40 -0
- package/src/modules/admin-account/components/update.tsx +263 -0
- package/src/modules/admin-account/errors.ts +75 -0
- package/src/modules/admin-account/index.ts +60 -0
- package/src/modules/admin-account/schemas.ts +84 -0
- package/src/modules/admin-account/service.ts +92 -0
- package/src/modules/admin-permissions/abilities.ts +46 -0
- package/src/modules/admin-permissions/commands.ts +103 -0
- package/src/modules/admin-permissions/components/inspector.module.css +326 -0
- package/src/modules/admin-permissions/components/inspector.tsx +298 -0
- package/src/modules/admin-permissions/dto.ts +28 -0
- package/src/modules/admin-permissions/errors.ts +57 -0
- package/src/modules/admin-permissions/index.ts +72 -0
- package/src/modules/admin-permissions/repository.ts +49 -0
- package/src/modules/admin-permissions/schemas.ts +128 -0
- package/src/modules/admin-permissions/service.ts +137 -0
- package/src/modules/admin-roles/abilities.ts +62 -0
- package/src/modules/admin-roles/commands.ts +161 -0
- package/src/modules/admin-roles/components/create.module.css +40 -0
- package/src/modules/admin-roles/components/create.tsx +218 -0
- package/src/modules/admin-roles/components/permissions.module.css +279 -0
- package/src/modules/admin-roles/components/permissions.tsx +396 -0
- package/src/modules/admin-roles/components/update.module.css +40 -0
- package/src/modules/admin-roles/components/update.tsx +218 -0
- package/src/modules/admin-roles/dto.ts +30 -0
- package/src/modules/admin-roles/errors.ts +76 -0
- package/src/modules/admin-roles/index.ts +81 -0
- package/src/modules/admin-roles/repository.ts +96 -0
- package/src/modules/admin-roles/schemas.ts +139 -0
- package/src/modules/admin-roles/service.ts +136 -0
- package/src/modules/admin-users/abilities.ts +76 -0
- package/src/modules/admin-users/commands.ts +157 -0
- package/src/modules/admin-users/components/create.module.css +63 -0
- package/src/modules/admin-users/components/create.tsx +323 -0
- package/src/modules/admin-users/components/roles.module.css +119 -0
- package/src/modules/admin-users/components/roles.tsx +172 -0
- package/src/modules/admin-users/components/set-password.module.css +46 -0
- package/src/modules/admin-users/components/set-password.tsx +199 -0
- package/src/modules/admin-users/components/update.module.css +49 -0
- package/src/modules/admin-users/components/update.tsx +328 -0
- package/src/modules/admin-users/dto.ts +39 -0
- package/src/modules/admin-users/errors.ts +84 -0
- package/src/modules/admin-users/index.ts +91 -0
- package/src/modules/admin-users/repository.ts +161 -0
- package/src/modules/admin-users/schemas.ts +168 -0
- package/src/modules/admin-users/seed-super-admin.ts +102 -0
- package/src/modules/admin-users/service.ts +166 -0
- package/src/modules/auth/components/sign-in-form.module.css +62 -0
- package/src/modules/auth/components/sign-in-form.tsx +132 -0
- package/src/modules/auth/index.ts +31 -0
- package/src/modules/auth/jwt-session-provider.ts +301 -0
- package/src/modules/auth/password.ts +94 -0
- package/src/modules/auth/phc.ts +121 -0
- package/src/modules/auth/refresh-tokens-repository.ts +74 -0
- package/src/modules/auth/resolve-actor.ts +42 -0
- package/src/services/admin-services-context.tsx +52 -0
- package/src/services/admin-services-types.ts +177 -0
- package/src/store.ts +32 -0
- package/src/vendor/noble-argon2/LICENSE +21 -0
- package/src/vendor/noble-argon2/README.md +87 -0
- package/src/vendor/noble-argon2/_blake.ts +58 -0
- package/src/vendor/noble-argon2/_md.ts +223 -0
- package/src/vendor/noble-argon2/_u64.ts +118 -0
- package/src/vendor/noble-argon2/argon2.ts +668 -0
- package/src/vendor/noble-argon2/blake2.ts +583 -0
- package/src/vendor/noble-argon2/utils.ts +849 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
:is(.wrap-d0Vkmj, .byline-account-update-wrap) {
|
|
2
|
+
gap: var(--spacing-8);
|
|
3
|
+
padding: var(--spacing-4);
|
|
4
|
+
margin-top: var(--spacing-4);
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
display: flex;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
:is(.form-VjOmD9, .byline-account-update-form) {
|
|
10
|
+
gap: var(--spacing-16);
|
|
11
|
+
padding-top: var(--spacing-8);
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
display: flex;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:is(.actions-QYTC9w, .byline-account-update-actions) {
|
|
17
|
+
justify-content: flex-end;
|
|
18
|
+
align-items: center;
|
|
19
|
+
gap: var(--spacing-8);
|
|
20
|
+
margin-top: var(--spacing-16);
|
|
21
|
+
display: flex;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:is(.action-Qs2VUY, .byline-account-update-action) {
|
|
25
|
+
min-width: 4rem;
|
|
26
|
+
}
|
|
27
|
+
|
|
@@ -1,51 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
-
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) Infonomic Company Limited
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Module-local error codes for admin-account self-service.
|
|
10
|
-
*
|
|
11
|
-
* Same `code + factory` shape as the other admin modules. The codes are
|
|
12
|
-
* prefixed `admin.account.*` so they sort alongside any future
|
|
13
|
-
* `admin.account` ability keys (today there are none — self-service is
|
|
14
|
-
* gated only by "you must be authenticated and you can only act on
|
|
15
|
-
* yourself") and so transport layers can branch on them distinctly
|
|
16
|
-
* from `admin.users.*`. Note that `admin.users.versionConflict` and
|
|
17
|
-
* `admin.users.emailInUse` are also reachable here because the service
|
|
18
|
-
* delegates to `AdminUsersRepository.update` / `setPasswordHash`; both
|
|
19
|
-
* are deliberately surfaced unmodified so the UI sees a single error
|
|
20
|
-
* code per condition.
|
|
21
|
-
*/
|
|
22
|
-
export const AdminAccountErrorCodes = {
|
|
1
|
+
const AdminAccountErrorCodes = {
|
|
23
2
|
NOT_FOUND: 'admin.account.notFound',
|
|
24
|
-
INVALID_CURRENT_PASSWORD: 'admin.account.invalidCurrentPassword'
|
|
3
|
+
INVALID_CURRENT_PASSWORD: 'admin.account.invalidCurrentPassword'
|
|
25
4
|
};
|
|
26
|
-
|
|
27
|
-
code
|
|
28
|
-
|
|
29
|
-
|
|
5
|
+
class AdminAccountError extends Error {
|
|
6
|
+
constructor(code, options){
|
|
7
|
+
super(options.message, null != options.cause ? {
|
|
8
|
+
cause: options.cause
|
|
9
|
+
} : void 0);
|
|
30
10
|
this.name = 'AdminAccountError';
|
|
31
11
|
this.code = code;
|
|
32
12
|
}
|
|
33
13
|
}
|
|
34
|
-
const make = (code, defaultMessage)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* — the transport handler should clear cookies and redirect to
|
|
42
|
-
* sign-in.
|
|
43
|
-
*/
|
|
44
|
-
export const ERR_ADMIN_ACCOUNT_NOT_FOUND = make(AdminAccountErrorCodes.NOT_FOUND, 'admin account not found');
|
|
45
|
-
/**
|
|
46
|
-
* The supplied current password did not verify against the stored hash.
|
|
47
|
-
* Returned for the change-password flow — message is intentionally
|
|
48
|
-
* generic so it can be surfaced verbatim to end users without leaking
|
|
49
|
-
* timing or existence signals.
|
|
50
|
-
*/
|
|
51
|
-
export const ERR_ADMIN_ACCOUNT_INVALID_CURRENT_PASSWORD = make(AdminAccountErrorCodes.INVALID_CURRENT_PASSWORD, 'current password is incorrect');
|
|
14
|
+
const make = (code, defaultMessage)=>(options)=>new AdminAccountError(code, {
|
|
15
|
+
message: options?.message ?? defaultMessage,
|
|
16
|
+
cause: options?.cause
|
|
17
|
+
});
|
|
18
|
+
const ERR_ADMIN_ACCOUNT_NOT_FOUND = make(AdminAccountErrorCodes.NOT_FOUND, 'admin account not found');
|
|
19
|
+
const ERR_ADMIN_ACCOUNT_INVALID_CURRENT_PASSWORD = make(AdminAccountErrorCodes.INVALID_CURRENT_PASSWORD, 'current password is incorrect');
|
|
20
|
+
export { AdminAccountError, AdminAccountErrorCodes, ERR_ADMIN_ACCOUNT_INVALID_CURRENT_PASSWORD, ERR_ADMIN_ACCOUNT_NOT_FOUND };
|
|
@@ -1,34 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) Infonomic Company Limited
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* `@byline/admin/admin-account` — self-service surfaces for the currently
|
|
10
|
-
* signed-in admin user.
|
|
11
|
-
*
|
|
12
|
-
* Distinct from `@byline/admin/admin-users` in two ways:
|
|
13
|
-
*
|
|
14
|
-
* 1. The actor IS the target. Commands take no `id` field — the
|
|
15
|
-
* target is sourced from `actor.id` on the authenticated
|
|
16
|
-
* `RequestContext`. There is no way at the command surface to
|
|
17
|
-
* ask "operate on someone else."
|
|
18
|
-
* 2. There is no ability gate. The other admin modules use
|
|
19
|
-
* `assertAdminActor(context, ability)`; this module uses
|
|
20
|
-
* `requireAdminActor(context)` — authn-only. "Anyone may change
|
|
21
|
-
* their own password" is the policy.
|
|
22
|
-
*
|
|
23
|
-
* Reuses `AdminUsersRepository` from `@byline/admin/admin-users` rather
|
|
24
|
-
* than introducing a parallel repo — the table is the same and the
|
|
25
|
-
* narrower self-service surface is structural rather than physical.
|
|
26
|
-
*
|
|
27
|
-
* Active-session listing / revocation is intentionally not included
|
|
28
|
-
* yet — that depends on `RefreshTokensRepository` semantics and a
|
|
29
|
-
* "sign out everywhere on password change" follow-up.
|
|
30
|
-
*/
|
|
31
|
-
export { changeAccountPasswordCommand, getAccountCommand, updateAccountCommand, } from './commands.js';
|
|
32
|
-
export { AdminAccountError, AdminAccountErrorCodes, ERR_ADMIN_ACCOUNT_INVALID_CURRENT_PASSWORD, ERR_ADMIN_ACCOUNT_NOT_FOUND, } from './errors.js';
|
|
33
|
-
export { accountResponseSchema, changeAccountPasswordRequestSchema, getAccountRequestSchema, okResponseSchema, updateAccountRequestSchema, } from './schemas.js';
|
|
34
|
-
export { AdminAccountService } from './service.js';
|
|
1
|
+
export { changeAccountPasswordCommand, getAccountCommand, updateAccountCommand } from "./commands.js";
|
|
2
|
+
export { AdminAccountError, AdminAccountErrorCodes, ERR_ADMIN_ACCOUNT_INVALID_CURRENT_PASSWORD, ERR_ADMIN_ACCOUNT_NOT_FOUND } from "./errors.js";
|
|
3
|
+
export { accountResponseSchema, changeAccountPasswordRequestSchema, getAccountRequestSchema, okResponseSchema, updateAccountRequestSchema } from "./schemas.js";
|
|
4
|
+
export { AdminAccountService } from "./service.js";
|
|
@@ -1,68 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
* - The actor IS the target. None of the request schemas accept an
|
|
14
|
-
* `id` field — the command resolves the target from
|
|
15
|
-
* `actor.id`. Persisting `id` in the request shape would
|
|
16
|
-
* immediately invite "but what if I pass someone else's id?"
|
|
17
|
-
* mistakes downstream.
|
|
18
|
-
* - The update patch excludes `is_super_admin`, `is_enabled`, and
|
|
19
|
-
* `is_email_verified`. Self-service must never let a user grant
|
|
20
|
-
* themselves super-admin or flip their own enabled state. Those
|
|
21
|
-
* fields stay editable through the admin-users module by an admin
|
|
22
|
-
* who holds the relevant ability.
|
|
23
|
-
* - `changePassword` requires the *current* password as a defence
|
|
24
|
-
* against session-hijack abuse: an attacker with a stolen session
|
|
25
|
-
* cookie still needs the password they don't have to swap it out.
|
|
26
|
-
*
|
|
27
|
-
* The response shape is the same as `adminUserResponseSchema` so the
|
|
28
|
-
* admin-account UI and the admin-users UI render the same row shape
|
|
29
|
-
* — re-exported here for convenience.
|
|
30
|
-
*/
|
|
31
|
-
import { passwordSchema } from '@byline/core/validation';
|
|
32
|
-
import { z } from 'zod';
|
|
33
|
-
import { adminUserResponseSchema, okResponseSchema } from '../admin-users/schemas.js';
|
|
34
|
-
const vidSchema = z
|
|
35
|
-
.number({ message: 'vid is required' })
|
|
36
|
-
.int({ message: 'vid must be an integer' })
|
|
37
|
-
.positive({ message: 'vid must be positive' });
|
|
38
|
-
const emailSchema = z
|
|
39
|
-
.email({ message: 'email must be a valid address' })
|
|
40
|
-
.min(3)
|
|
41
|
-
.max(254)
|
|
42
|
-
.transform((v) => v.toLowerCase());
|
|
1
|
+
import { passwordSchema } from "@byline/core/validation";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const vidSchema = z.number({
|
|
4
|
+
message: 'vid is required'
|
|
5
|
+
}).int({
|
|
6
|
+
message: 'vid must be an integer'
|
|
7
|
+
}).positive({
|
|
8
|
+
message: 'vid must be positive'
|
|
9
|
+
});
|
|
10
|
+
const emailSchema = z.email({
|
|
11
|
+
message: 'email must be a valid address'
|
|
12
|
+
}).min(3).max(254).transform((v)=>v.toLowerCase());
|
|
43
13
|
const nameSchema = z.string().min(1).max(100);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// ---------------------------------------------------------------------------
|
|
47
|
-
/** No payload — target is the actor on context. */
|
|
48
|
-
export const getAccountRequestSchema = z.object({}).strict();
|
|
49
|
-
export const updateAccountRequestSchema = z.object({
|
|
14
|
+
const getAccountRequestSchema = z.object({}).strict();
|
|
15
|
+
const updateAccountRequestSchema = z.object({
|
|
50
16
|
vid: vidSchema,
|
|
51
|
-
patch: z
|
|
52
|
-
.object({
|
|
17
|
+
patch: z.object({
|
|
53
18
|
email: emailSchema.optional(),
|
|
54
19
|
given_name: nameSchema.nullish(),
|
|
55
20
|
family_name: nameSchema.nullish(),
|
|
56
|
-
username: z.string().min(1).max(100).nullish()
|
|
21
|
+
username: z.string().min(1).max(100).nullish()
|
|
22
|
+
}).refine((p)=>Object.keys(p).length > 0, {
|
|
23
|
+
message: 'patch cannot be empty'
|
|
57
24
|
})
|
|
58
|
-
.refine((p) => Object.keys(p).length > 0, { message: 'patch cannot be empty' }),
|
|
59
25
|
});
|
|
60
|
-
|
|
26
|
+
const changeAccountPasswordRequestSchema = z.object({
|
|
61
27
|
vid: vidSchema,
|
|
62
|
-
currentPassword: z.string().min(1, {
|
|
63
|
-
|
|
28
|
+
currentPassword: z.string().min(1, {
|
|
29
|
+
message: 'current password is required'
|
|
30
|
+
}),
|
|
31
|
+
newPassword: passwordSchema
|
|
64
32
|
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
export { adminUserResponseSchema as accountResponseSchema, okResponseSchema };
|
|
33
|
+
export { adminUserResponseSchema as accountResponseSchema, okResponseSchema } from "../admin-users/schemas.js";
|
|
34
|
+
export { changeAccountPasswordRequestSchema, getAccountRequestSchema, updateAccountRequestSchema };
|
|
@@ -1,75 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* just a narrower surface over it. The narrowing is structural:
|
|
18
|
-
*
|
|
19
|
-
* - Every method takes `actorId` (sourced server-side from the
|
|
20
|
-
* authenticated `RequestContext`) and uses it as the target id.
|
|
21
|
-
* Callers cannot supply a target id; commands look it up from
|
|
22
|
-
* `actor.id` and pass it in.
|
|
23
|
-
* - `updateAccount` excludes `is_super_admin`, `is_enabled`, and
|
|
24
|
-
* `is_email_verified` from the writable surface. The schema
|
|
25
|
-
* already strips them, but the service signature reinforces it.
|
|
26
|
-
* - `changePassword` verifies the *current* password before swapping
|
|
27
|
-
* in the new hash. A hijacked session cannot use this flow to lock
|
|
28
|
-
* out the legitimate owner.
|
|
29
|
-
*
|
|
30
|
-
* Note on session revocation: changing a password here does **not**
|
|
31
|
-
* currently revoke other refresh tokens — existing access tokens stay
|
|
32
|
-
* valid until their 15-minute expiry, and other refresh tokens remain
|
|
33
|
-
* useable. A "sign out everywhere on password change" follow-up should
|
|
34
|
-
* call `RefreshTokensRepository.revokeAllExcept(adminUserId, currentJti)`
|
|
35
|
-
* once that lands.
|
|
36
|
-
*/
|
|
37
|
-
export class AdminAccountService {
|
|
38
|
-
#repo;
|
|
39
|
-
constructor(deps) {
|
|
40
|
-
this.#repo = deps.repo;
|
|
1
|
+
import { toAdminUser } from "../admin-users/dto.js";
|
|
2
|
+
import { ERR_ADMIN_USER_EMAIL_IN_USE } from "../admin-users/errors.js";
|
|
3
|
+
import { hashPassword, verifyPassword } from "../auth/password.js";
|
|
4
|
+
import { ERR_ADMIN_ACCOUNT_INVALID_CURRENT_PASSWORD, ERR_ADMIN_ACCOUNT_NOT_FOUND } from "./errors.js";
|
|
5
|
+
function _check_private_redeclaration(obj, privateCollection) {
|
|
6
|
+
if (privateCollection.has(obj)) throw new TypeError("Cannot initialize the same private elements twice on an object");
|
|
7
|
+
}
|
|
8
|
+
function _class_apply_descriptor_get(receiver, descriptor) {
|
|
9
|
+
if (descriptor.get) return descriptor.get.call(receiver);
|
|
10
|
+
return descriptor.value;
|
|
11
|
+
}
|
|
12
|
+
function _class_apply_descriptor_set(receiver, descriptor, value) {
|
|
13
|
+
if (descriptor.set) descriptor.set.call(receiver, value);
|
|
14
|
+
else {
|
|
15
|
+
if (!descriptor.writable) throw new TypeError("attempted to set read only private field");
|
|
16
|
+
descriptor.value = value;
|
|
41
17
|
}
|
|
18
|
+
}
|
|
19
|
+
function _class_extract_field_descriptor(receiver, privateMap, action) {
|
|
20
|
+
if (!privateMap.has(receiver)) throw new TypeError("attempted to " + action + " private field on non-instance");
|
|
21
|
+
return privateMap.get(receiver);
|
|
22
|
+
}
|
|
23
|
+
function _class_private_field_get(receiver, privateMap) {
|
|
24
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
|
|
25
|
+
return _class_apply_descriptor_get(receiver, descriptor);
|
|
26
|
+
}
|
|
27
|
+
function _class_private_field_init(obj, privateMap, value) {
|
|
28
|
+
_check_private_redeclaration(obj, privateMap);
|
|
29
|
+
privateMap.set(obj, value);
|
|
30
|
+
}
|
|
31
|
+
function _class_private_field_set(receiver, privateMap, value) {
|
|
32
|
+
var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
|
|
33
|
+
_class_apply_descriptor_set(receiver, descriptor, value);
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
var _repo = /*#__PURE__*/ new WeakMap();
|
|
37
|
+
class AdminAccountService {
|
|
42
38
|
async getAccount(actorId) {
|
|
43
|
-
const row = await this
|
|
44
|
-
if (!row)
|
|
45
|
-
throw ERR_ADMIN_ACCOUNT_NOT_FOUND();
|
|
39
|
+
const row = await _class_private_field_get(this, _repo).getById(actorId);
|
|
40
|
+
if (!row) throw ERR_ADMIN_ACCOUNT_NOT_FOUND();
|
|
46
41
|
return toAdminUser(row);
|
|
47
42
|
}
|
|
48
43
|
async updateAccount(actorId, request) {
|
|
49
|
-
const current = await this
|
|
50
|
-
if (!current)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (owner && owner.id !== actorId)
|
|
55
|
-
throw ERR_ADMIN_USER_EMAIL_IN_USE();
|
|
44
|
+
const current = await _class_private_field_get(this, _repo).getById(actorId);
|
|
45
|
+
if (!current) throw ERR_ADMIN_ACCOUNT_NOT_FOUND();
|
|
46
|
+
if (null != request.patch.email && request.patch.email !== current.email) {
|
|
47
|
+
const owner = await _class_private_field_get(this, _repo).getByEmail(request.patch.email);
|
|
48
|
+
if (owner && owner.id !== actorId) throw ERR_ADMIN_USER_EMAIL_IN_USE();
|
|
56
49
|
}
|
|
57
|
-
const row = await this
|
|
50
|
+
const row = await _class_private_field_get(this, _repo).update(actorId, request.vid, request.patch);
|
|
58
51
|
return toAdminUser(row);
|
|
59
52
|
}
|
|
60
53
|
async changePassword(actorId, request) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// sign-in-shaped row is treated as ephemeral here — the hash
|
|
64
|
-
// string is never propagated outside this method.
|
|
65
|
-
const withHash = await this.#repo.getByIdForSignIn(actorId);
|
|
66
|
-
if (!withHash)
|
|
67
|
-
throw ERR_ADMIN_ACCOUNT_NOT_FOUND();
|
|
54
|
+
const withHash = await _class_private_field_get(this, _repo).getByIdForSignIn(actorId);
|
|
55
|
+
if (!withHash) throw ERR_ADMIN_ACCOUNT_NOT_FOUND();
|
|
68
56
|
const ok = await verifyPassword(request.currentPassword, withHash.password_hash);
|
|
69
|
-
if (!ok)
|
|
70
|
-
throw ERR_ADMIN_ACCOUNT_INVALID_CURRENT_PASSWORD();
|
|
57
|
+
if (!ok) throw ERR_ADMIN_ACCOUNT_INVALID_CURRENT_PASSWORD();
|
|
71
58
|
const newHash = await hashPassword(request.newPassword);
|
|
72
|
-
const row = await this
|
|
59
|
+
const row = await _class_private_field_get(this, _repo).setPasswordHash(actorId, request.vid, newHash);
|
|
73
60
|
return toAdminUser(row);
|
|
74
61
|
}
|
|
62
|
+
constructor(deps){
|
|
63
|
+
_class_private_field_init(this, _repo, {
|
|
64
|
+
writable: true,
|
|
65
|
+
value: void 0
|
|
66
|
+
});
|
|
67
|
+
_class_private_field_set(this, _repo, deps.repo);
|
|
68
|
+
}
|
|
75
69
|
}
|
|
70
|
+
export { AdminAccountService };
|
|
@@ -1,39 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
-
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
-
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) Infonomic Company Limited
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Ability keys for the admin-permissions module.
|
|
10
|
-
*
|
|
11
|
-
* `read` gates the inspector view (see docs/AUTHN-AUTHZ.md).
|
|
12
|
-
* `update` will gate the per-role ability editor mounted on the
|
|
13
|
-
* admin-roles role detail page — declared here so the role editor can
|
|
14
|
-
* assert against it once that surface lands. The per-role editor shares
|
|
15
|
-
* the `update` key rather than minting `grant` / `revoke` keys: granting
|
|
16
|
-
* abilities to a role is a single editorial operation from the admin's
|
|
17
|
-
* perspective, and a granular split would force a redundant key on
|
|
18
|
-
* every permission-managing role.
|
|
19
|
-
*/
|
|
20
|
-
export const ADMIN_PERMISSIONS_ABILITIES = {
|
|
1
|
+
const ADMIN_PERMISSIONS_ABILITIES = {
|
|
21
2
|
read: 'admin.permissions.read',
|
|
22
|
-
update: 'admin.permissions.update'
|
|
3
|
+
update: 'admin.permissions.update'
|
|
23
4
|
};
|
|
24
|
-
|
|
5
|
+
function registerAdminPermissionsAbilities(registry) {
|
|
25
6
|
registry.register({
|
|
26
7
|
key: ADMIN_PERMISSIONS_ABILITIES.read,
|
|
27
8
|
label: 'Read admin permissions',
|
|
28
9
|
description: 'View the abilities inspector and per-role ability grants.',
|
|
29
10
|
group: 'admin.permissions',
|
|
30
|
-
source: 'admin'
|
|
11
|
+
source: 'admin'
|
|
31
12
|
});
|
|
32
13
|
registry.register({
|
|
33
14
|
key: ADMIN_PERMISSIONS_ABILITIES.update,
|
|
34
15
|
label: 'Update admin permissions',
|
|
35
16
|
description: "Edit a role's ability grants.",
|
|
36
17
|
group: 'admin.permissions',
|
|
37
|
-
source: 'admin'
|
|
18
|
+
source: 'admin'
|
|
38
19
|
});
|
|
39
20
|
}
|
|
21
|
+
export { ADMIN_PERMISSIONS_ABILITIES, registerAdminPermissionsAbilities };
|
|
@@ -1,41 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) Infonomic Company Limited
|
|
7
|
-
*/
|
|
8
|
-
import { createCommand } from '../../lib/create-command.js';
|
|
9
|
-
import { ADMIN_PERMISSIONS_ABILITIES } from './abilities.js';
|
|
10
|
-
import { getRoleAbilitiesRequestSchema, getRoleAbilitiesResponseSchema, listRegisteredAbilitiesRequestSchema, listRegisteredAbilitiesResponseSchema, setRoleAbilitiesRequestSchema, setRoleAbilitiesResponseSchema, whoHasAbilityRequestSchema, whoHasAbilityResponseSchema, } from './schemas.js';
|
|
11
|
-
import { AdminPermissionsService } from './service.js';
|
|
1
|
+
import { createCommand } from "../../lib/create-command.js";
|
|
2
|
+
import { ADMIN_PERMISSIONS_ABILITIES } from "./abilities.js";
|
|
3
|
+
import { getRoleAbilitiesRequestSchema, getRoleAbilitiesResponseSchema, listRegisteredAbilitiesRequestSchema, listRegisteredAbilitiesResponseSchema, setRoleAbilitiesRequestSchema, setRoleAbilitiesResponseSchema, whoHasAbilityRequestSchema, whoHasAbilityResponseSchema } from "./schemas.js";
|
|
4
|
+
import { AdminPermissionsService } from "./service.js";
|
|
12
5
|
function serviceOf(deps) {
|
|
13
|
-
return new AdminPermissionsService({
|
|
6
|
+
return new AdminPermissionsService({
|
|
7
|
+
store: deps.store,
|
|
8
|
+
abilities: deps.abilities
|
|
9
|
+
});
|
|
14
10
|
}
|
|
15
|
-
|
|
11
|
+
const listRegisteredAbilitiesCommand = createCommand({
|
|
16
12
|
method: 'listRegisteredAbilities',
|
|
17
|
-
auth: {
|
|
13
|
+
auth: {
|
|
14
|
+
ability: ADMIN_PERMISSIONS_ABILITIES.read
|
|
15
|
+
},
|
|
18
16
|
schemas: {
|
|
19
17
|
input: listRegisteredAbilitiesRequestSchema,
|
|
20
|
-
output: listRegisteredAbilitiesResponseSchema
|
|
18
|
+
output: listRegisteredAbilitiesResponseSchema
|
|
21
19
|
},
|
|
22
|
-
handler: ({ deps })
|
|
20
|
+
handler: ({ deps })=>serviceOf(deps).listRegisteredAbilities()
|
|
23
21
|
});
|
|
24
|
-
|
|
22
|
+
const whoHasAbilityCommand = createCommand({
|
|
25
23
|
method: 'whoHasAbility',
|
|
26
|
-
auth: {
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
auth: {
|
|
25
|
+
ability: ADMIN_PERMISSIONS_ABILITIES.read
|
|
26
|
+
},
|
|
27
|
+
schemas: {
|
|
28
|
+
input: whoHasAbilityRequestSchema,
|
|
29
|
+
output: whoHasAbilityResponseSchema
|
|
30
|
+
},
|
|
31
|
+
handler: ({ input, deps })=>serviceOf(deps).whoHasAbility(input)
|
|
29
32
|
});
|
|
30
|
-
|
|
33
|
+
const getRoleAbilitiesCommand = createCommand({
|
|
31
34
|
method: 'getRoleAbilities',
|
|
32
|
-
auth: {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
auth: {
|
|
36
|
+
ability: ADMIN_PERMISSIONS_ABILITIES.read
|
|
37
|
+
},
|
|
38
|
+
schemas: {
|
|
39
|
+
input: getRoleAbilitiesRequestSchema,
|
|
40
|
+
output: getRoleAbilitiesResponseSchema
|
|
41
|
+
},
|
|
42
|
+
handler: ({ input, deps })=>serviceOf(deps).getRoleAbilities(input)
|
|
35
43
|
});
|
|
36
|
-
|
|
44
|
+
const setRoleAbilitiesCommand = createCommand({
|
|
37
45
|
method: 'setRoleAbilities',
|
|
38
|
-
auth: {
|
|
39
|
-
|
|
40
|
-
|
|
46
|
+
auth: {
|
|
47
|
+
ability: ADMIN_PERMISSIONS_ABILITIES.update
|
|
48
|
+
},
|
|
49
|
+
schemas: {
|
|
50
|
+
input: setRoleAbilitiesRequestSchema,
|
|
51
|
+
output: setRoleAbilitiesResponseSchema
|
|
52
|
+
},
|
|
53
|
+
handler: ({ input, deps })=>serviceOf(deps).setRoleAbilities(input)
|
|
41
54
|
});
|
|
55
|
+
export { getRoleAbilitiesCommand, listRegisteredAbilitiesCommand, setRoleAbilitiesCommand, whoHasAbilityCommand };
|