@byline/admin 2.4.0 → 2.4.2
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
package/dist/abilities.js
CHANGED
|
@@ -1,28 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) Infonomic Company Limited
|
|
7
|
-
*/
|
|
8
|
-
import { registerAdminPermissionsAbilities } from './modules/admin-permissions/abilities.js';
|
|
9
|
-
import { registerAdminRolesAbilities } from './modules/admin-roles/abilities.js';
|
|
10
|
-
import { registerAdminUsersAbilities } from './modules/admin-users/abilities.js';
|
|
11
|
-
/**
|
|
12
|
-
* Register every ability contributed by the admin subsystem.
|
|
13
|
-
*
|
|
14
|
-
* Called once at `initBylineCore()` time from the webapp config. Each
|
|
15
|
-
* admin module contributes its own registrar (`registerAdminUsersAbilities`,
|
|
16
|
-
* `registerAdminRolesAbilities`, …); this function fans out to them so
|
|
17
|
-
* the webapp wiring stays a single line.
|
|
18
|
-
*
|
|
19
|
-
* Admin does not self-register from core to keep the `@byline/core`
|
|
20
|
-
* package free of a dependency on `@byline/admin` — the registration
|
|
21
|
-
* call is an opt-in at the composition root.
|
|
22
|
-
*/
|
|
23
|
-
export function registerAdminAbilities(registry) {
|
|
1
|
+
import { registerAdminPermissionsAbilities } from "./modules/admin-permissions/abilities.js";
|
|
2
|
+
import { registerAdminRolesAbilities } from "./modules/admin-roles/abilities.js";
|
|
3
|
+
import { registerAdminUsersAbilities } from "./modules/admin-users/abilities.js";
|
|
4
|
+
function registerAdminAbilities(registry) {
|
|
24
5
|
registerAdminUsersAbilities(registry);
|
|
25
6
|
registerAdminRolesAbilities(registry);
|
|
26
7
|
registerAdminPermissionsAbilities(registry);
|
|
27
|
-
// registerAccountAbilities(registry) — added when that module lands
|
|
28
8
|
}
|
|
9
|
+
export { registerAdminAbilities };
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* `@byline/admin` — the admin subsystem.
|
|
10
|
-
*
|
|
11
|
-
* Concrete implementation of the admin side of Byline: admin users,
|
|
12
|
-
* roles, permissions, account self-service, and the built-in JWT
|
|
13
|
-
* session provider. Depends on `@byline/auth` (the Actor / RequestContext
|
|
14
|
-
* / SessionProvider contract) and `@byline/core` (collection and lifecycle
|
|
15
|
-
* machinery). Third-party session providers (Lucia, WorkOS, Clerk, SSO)
|
|
16
|
-
* are intentionally kept out of this package — they live as separate
|
|
17
|
-
* adapters against `@byline/auth` directly.
|
|
18
|
-
*
|
|
19
|
-
* Prefer the per-module subpath exports (`@byline/admin/admin-users`,
|
|
20
|
-
* `@byline/admin/auth`, etc.) over the root barrel; this root exists so
|
|
21
|
-
* the package is importable as a single unit when that is convenient.
|
|
22
|
-
*/
|
|
23
|
-
export { registerAdminAbilities } from './abilities.js';
|
|
24
|
-
export { assertAdminActor, requireAdminActor } from './lib/assert-admin-actor.js';
|
|
25
|
-
export { createCommand, } from './lib/create-command.js';
|
|
26
|
-
export * from './modules/admin-account/index.js';
|
|
27
|
-
export * from './modules/admin-permissions/index.js';
|
|
28
|
-
export * from './modules/admin-roles/index.js';
|
|
29
|
-
export * from './modules/admin-users/index.js';
|
|
30
|
-
export * from './modules/auth/index.js';
|
|
1
|
+
export * from "./modules/admin-account/index.js";
|
|
2
|
+
export * from "./modules/admin-permissions/index.js";
|
|
3
|
+
export * from "./modules/admin-roles/index.js";
|
|
4
|
+
export * from "./modules/admin-users/index.js";
|
|
5
|
+
export * from "./modules/auth/index.js";
|
|
6
|
+
export { registerAdminAbilities } from "./abilities.js";
|
|
7
|
+
export { assertAdminActor, requireAdminActor } from "./lib/assert-admin-actor.js";
|
|
8
|
+
export { createCommand } from "./lib/create-command.js";
|
|
@@ -1,81 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
-
import { ERR_UNAUTHENTICATED, isAdminAuth } from '@byline/auth';
|
|
9
|
-
/**
|
|
10
|
-
* Gate every admin command behind three checks, in order:
|
|
11
|
-
*
|
|
12
|
-
* 1. `context` exists. No in-process call may reach an admin command
|
|
13
|
-
* without threading a `RequestContext` — seeds/tests pass
|
|
14
|
-
* `createSuperAdminContext()`.
|
|
15
|
-
* 2. `context.actor` is an `AdminAuth`. Anonymous admin calls are
|
|
16
|
-
* rejected outright — admin actions are never public. A `UserAuth`
|
|
17
|
-
* (end-user identity) also fails here: it may sign in against the
|
|
18
|
-
* app realm, but it does not have an admin identity.
|
|
19
|
-
* 3. The actor holds the required ability. `AdminAuth.assertAbility`
|
|
20
|
-
* short-circuits on `isSuperAdmin: true`; otherwise the flat
|
|
21
|
-
* ability set is consulted.
|
|
22
|
-
*
|
|
23
|
-
* Returns the narrowed `AdminAuth` so callers can use it without a
|
|
24
|
-
* second type guard — the typical shape is:
|
|
25
|
-
*
|
|
26
|
-
* ```ts
|
|
27
|
-
* export async function deleteAdminUserCommand(context, input, deps) {
|
|
28
|
-
* const parsed = deleteAdminUserRequestSchema.parse(input)
|
|
29
|
-
* const actor = assertAdminActor(context, ADMIN_USERS_ABILITIES.delete)
|
|
30
|
-
* return service.deleteUser(actor, parsed)
|
|
31
|
-
* }
|
|
32
|
-
* ```
|
|
33
|
-
*
|
|
34
|
-
* The three failures produce distinct error codes:
|
|
35
|
-
* - missing context / missing actor / wrong actor type → `ERR_UNAUTHENTICATED`
|
|
36
|
-
* - ability missing → `ERR_FORBIDDEN`
|
|
37
|
-
* (thrown from `AdminAuth.assertAbility`)
|
|
38
|
-
*/
|
|
39
|
-
export function assertAdminActor(context, ability) {
|
|
1
|
+
import { ERR_UNAUTHENTICATED, isAdminAuth } from "@byline/auth";
|
|
2
|
+
function assertAdminActor(context, ability) {
|
|
40
3
|
const actor = requireAdminActor(context, `admin action requiring '${ability}'`);
|
|
41
4
|
actor.assertAbility(ability);
|
|
42
5
|
return actor;
|
|
43
6
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
*
|
|
49
|
-
* Used by self-service commands where the actor is the target by
|
|
50
|
-
* definition — `@byline/admin/admin-account` for "change my own
|
|
51
|
-
* password" / "update my own profile". For those flows there is no
|
|
52
|
-
* meaningful ability to gate against; the security property is "you
|
|
53
|
-
* may only mutate your own row," and the commands enforce that by
|
|
54
|
-
* sourcing the target id from `actor.id` rather than from the
|
|
55
|
-
* request payload.
|
|
56
|
-
*
|
|
57
|
-
* Reasoning is described as part of the request narrative so the
|
|
58
|
-
* `ERR_UNAUTHENTICATED` message stays useful when it surfaces in logs
|
|
59
|
-
* — the helper has no `ability` argument to fall back on.
|
|
60
|
-
*/
|
|
61
|
-
export function requireAdminActor(context, reasonForLog) {
|
|
62
|
-
if (!context) {
|
|
63
|
-
throw ERR_UNAUTHENTICATED({
|
|
64
|
-
message: `missing requestContext on ${reasonForLog}. Pass createSuperAdminContext() ` +
|
|
65
|
-
`from @byline/auth for scripts/tests, or construct a request-scoped context from your ` +
|
|
66
|
-
`session provider in the admin webapp.`,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
7
|
+
function requireAdminActor(context, reasonForLog) {
|
|
8
|
+
if (!context) throw ERR_UNAUTHENTICATED({
|
|
9
|
+
message: `missing requestContext on ${reasonForLog}. Pass createSuperAdminContext() from @byline/auth for scripts/tests, or construct a request-scoped context from your session provider in the admin webapp.`
|
|
10
|
+
});
|
|
69
11
|
const { actor } = context;
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
throw ERR_UNAUTHENTICATED({
|
|
77
|
-
message: `non-admin actor cannot perform ${reasonForLog}`,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
12
|
+
if (null == actor) throw ERR_UNAUTHENTICATED({
|
|
13
|
+
message: `anonymous caller cannot perform ${reasonForLog}`
|
|
14
|
+
});
|
|
15
|
+
if (!isAdminAuth(actor)) throw ERR_UNAUTHENTICATED({
|
|
16
|
+
message: `non-admin actor cannot perform ${reasonForLog}`
|
|
17
|
+
});
|
|
80
18
|
return actor;
|
|
81
19
|
}
|
|
20
|
+
export { assertAdminActor, requireAdminActor };
|
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) Infonomic Company Limited
|
|
7
|
-
*/
|
|
8
|
-
import { assertAdminActor, requireAdminActor } from './assert-admin-actor.js';
|
|
9
|
-
export function createCommand(spec) {
|
|
10
|
-
return async function command(context, input, deps) {
|
|
1
|
+
import { assertAdminActor, requireAdminActor } from "./assert-admin-actor.js";
|
|
2
|
+
function createCommand(spec) {
|
|
3
|
+
return async function(context, input, deps) {
|
|
11
4
|
const parsed = spec.schemas.input.parse(input ?? {});
|
|
12
|
-
const actor = spec.auth.ability
|
|
13
|
-
? assertAdminActor(context, spec.auth.ability)
|
|
14
|
-
: requireAdminActor(context, spec.method);
|
|
15
|
-
// `context` is non-null after the auth step — both helpers throw
|
|
16
|
-
// `ERR_UNAUTHENTICATED` when the request context is missing.
|
|
5
|
+
const actor = void 0 !== spec.auth.ability ? assertAdminActor(context, spec.auth.ability) : requireAdminActor(context, spec.method);
|
|
17
6
|
const result = await spec.handler({
|
|
18
7
|
context: context,
|
|
19
8
|
input: parsed,
|
|
20
9
|
deps,
|
|
21
|
-
actor
|
|
10
|
+
actor
|
|
22
11
|
});
|
|
23
12
|
return spec.schemas.output.parse(result);
|
|
24
13
|
};
|
|
25
14
|
}
|
|
15
|
+
export { createCommand };
|
|
@@ -1,32 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) Infonomic Company Limited
|
|
7
|
-
*/
|
|
8
|
-
import { createCommand } from '../../lib/create-command.js';
|
|
9
|
-
import { adminUserResponseSchema } from '../admin-users/schemas.js';
|
|
10
|
-
import { changeAccountPasswordRequestSchema, getAccountRequestSchema, updateAccountRequestSchema, } from './schemas.js';
|
|
11
|
-
import { AdminAccountService } from './service.js';
|
|
1
|
+
import { createCommand } from "../../lib/create-command.js";
|
|
2
|
+
import { adminUserResponseSchema } from "../admin-users/schemas.js";
|
|
3
|
+
import { changeAccountPasswordRequestSchema, getAccountRequestSchema, updateAccountRequestSchema } from "./schemas.js";
|
|
4
|
+
import { AdminAccountService } from "./service.js";
|
|
12
5
|
function serviceOf(deps) {
|
|
13
|
-
return new AdminAccountService({
|
|
6
|
+
return new AdminAccountService({
|
|
7
|
+
repo: deps.store.adminUsers
|
|
8
|
+
});
|
|
14
9
|
}
|
|
15
|
-
|
|
10
|
+
const getAccountCommand = createCommand({
|
|
16
11
|
method: 'getAccount',
|
|
17
|
-
auth: {
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
auth: {
|
|
13
|
+
authenticated: true
|
|
14
|
+
},
|
|
15
|
+
schemas: {
|
|
16
|
+
input: getAccountRequestSchema,
|
|
17
|
+
output: adminUserResponseSchema
|
|
18
|
+
},
|
|
19
|
+
handler: ({ deps, actor })=>serviceOf(deps).getAccount(actor.id)
|
|
20
20
|
});
|
|
21
|
-
|
|
21
|
+
const updateAccountCommand = createCommand({
|
|
22
22
|
method: 'updateAccount',
|
|
23
|
-
auth: {
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
auth: {
|
|
24
|
+
authenticated: true
|
|
25
|
+
},
|
|
26
|
+
schemas: {
|
|
27
|
+
input: updateAccountRequestSchema,
|
|
28
|
+
output: adminUserResponseSchema
|
|
29
|
+
},
|
|
30
|
+
handler: ({ input, deps, actor })=>serviceOf(deps).updateAccount(actor.id, input)
|
|
26
31
|
});
|
|
27
|
-
|
|
32
|
+
const changeAccountPasswordCommand = createCommand({
|
|
28
33
|
method: 'changeAccountPassword',
|
|
29
|
-
auth: {
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
auth: {
|
|
35
|
+
authenticated: true
|
|
36
|
+
},
|
|
37
|
+
schemas: {
|
|
38
|
+
input: changeAccountPasswordRequestSchema,
|
|
39
|
+
output: adminUserResponseSchema
|
|
40
|
+
},
|
|
41
|
+
handler: ({ input, deps, actor })=>serviceOf(deps).changePassword(actor.id, input)
|
|
32
42
|
});
|
|
43
|
+
export { changeAccountPasswordCommand, getAccountCommand, updateAccountCommand };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AccountResponse } from '../index.js';
|
|
2
|
+
interface ChangePasswordProps {
|
|
3
|
+
account: AccountResponse;
|
|
4
|
+
onClose?: () => void;
|
|
5
|
+
onSuccess?: (account: AccountResponse) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare function ChangeAccountPassword({ account, onClose, onSuccess }: ChangePasswordProps): import("react").JSX.Element;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { revalidateLogic, useForm } from "@tanstack/react-form-start";
|
|
5
|
+
import { passwordSchema } from "@byline/core/validation";
|
|
6
|
+
import { Alert, Button, InputPassword, LoaderEllipsis } from "@byline/ui/react";
|
|
7
|
+
import classnames from "classnames";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { useBylineAdminServices } from "../../../services/admin-services-context.js";
|
|
10
|
+
import change_password_module from "./change-password.module.js";
|
|
11
|
+
const changePasswordFormSchema = z.object({
|
|
12
|
+
currentPassword: z.string().min(1, {
|
|
13
|
+
message: 'Please enter your current password'
|
|
14
|
+
}),
|
|
15
|
+
newPassword: passwordSchema,
|
|
16
|
+
confirm: z.string({
|
|
17
|
+
message: 'Please confirm the new password'
|
|
18
|
+
})
|
|
19
|
+
}).refine((v)=>v.newPassword === v.confirm, {
|
|
20
|
+
message: 'New passwords do not match',
|
|
21
|
+
path: [
|
|
22
|
+
'confirm'
|
|
23
|
+
]
|
|
24
|
+
});
|
|
25
|
+
function ChangeAccountPassword({ account, onClose, onSuccess }) {
|
|
26
|
+
const { changeAccountPassword } = useBylineAdminServices();
|
|
27
|
+
const [formError, setFormError] = useState(null);
|
|
28
|
+
const [successMessage, setSuccessMessage] = useState(null);
|
|
29
|
+
const form = useForm({
|
|
30
|
+
defaultValues: {
|
|
31
|
+
currentPassword: '',
|
|
32
|
+
newPassword: '',
|
|
33
|
+
confirm: ''
|
|
34
|
+
},
|
|
35
|
+
validationLogic: revalidateLogic({
|
|
36
|
+
mode: 'blur',
|
|
37
|
+
modeAfterSubmission: 'change'
|
|
38
|
+
}),
|
|
39
|
+
validators: {
|
|
40
|
+
onDynamic: changePasswordFormSchema
|
|
41
|
+
},
|
|
42
|
+
onSubmit: async ({ value })=>{
|
|
43
|
+
setFormError(null);
|
|
44
|
+
setSuccessMessage(null);
|
|
45
|
+
try {
|
|
46
|
+
const updated = await changeAccountPassword({
|
|
47
|
+
data: {
|
|
48
|
+
vid: account.vid,
|
|
49
|
+
currentPassword: value.currentPassword,
|
|
50
|
+
newPassword: value.newPassword
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
setSuccessMessage('Password updated.');
|
|
54
|
+
form.reset({
|
|
55
|
+
currentPassword: '',
|
|
56
|
+
newPassword: '',
|
|
57
|
+
confirm: ''
|
|
58
|
+
});
|
|
59
|
+
onSuccess?.(updated);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
const code = getErrorCode(err);
|
|
62
|
+
if ('admin.account.invalidCurrentPassword' === code) return void form.setFieldMeta('currentPassword', (meta)=>({
|
|
63
|
+
...meta,
|
|
64
|
+
errorMap: {
|
|
65
|
+
...meta.errorMap,
|
|
66
|
+
onServer: 'Current password is incorrect.'
|
|
67
|
+
},
|
|
68
|
+
errors: [
|
|
69
|
+
'Current password is incorrect.'
|
|
70
|
+
]
|
|
71
|
+
}));
|
|
72
|
+
if ('admin.users.versionConflict' === code) return void setFormError('Your account has been modified elsewhere since you opened this form. Reload to refresh and try again.');
|
|
73
|
+
if ('admin.account.notFound' === code) return void setFormError('Your admin account could not be found. Please sign in again.');
|
|
74
|
+
setFormError('Could not change the password. Please try again.');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
return /*#__PURE__*/ jsx("div", {
|
|
79
|
+
className: classnames('byline-account-change-password-wrap', change_password_module.wrap),
|
|
80
|
+
children: /*#__PURE__*/ jsxs("form", {
|
|
81
|
+
noValidate: true,
|
|
82
|
+
onSubmit: (event)=>{
|
|
83
|
+
event.preventDefault();
|
|
84
|
+
event.stopPropagation();
|
|
85
|
+
form.handleSubmit();
|
|
86
|
+
},
|
|
87
|
+
className: classnames('byline-account-change-password-form', change_password_module.form),
|
|
88
|
+
children: [
|
|
89
|
+
formError ? /*#__PURE__*/ jsx(Alert, {
|
|
90
|
+
intent: "danger",
|
|
91
|
+
children: formError
|
|
92
|
+
}) : null,
|
|
93
|
+
successMessage ? /*#__PURE__*/ jsx(Alert, {
|
|
94
|
+
intent: "success",
|
|
95
|
+
children: successMessage
|
|
96
|
+
}) : null,
|
|
97
|
+
/*#__PURE__*/ jsx("p", {
|
|
98
|
+
className: "muted",
|
|
99
|
+
children: "Other active sessions will continue to work until their tokens expire. Sign out elsewhere if you suspect another device has been compromised."
|
|
100
|
+
}),
|
|
101
|
+
/*#__PURE__*/ jsx(form.Field, {
|
|
102
|
+
name: "currentPassword",
|
|
103
|
+
children: (field)=>/*#__PURE__*/ jsx(InputPassword, {
|
|
104
|
+
label: "Current password",
|
|
105
|
+
id: "currentPassword",
|
|
106
|
+
name: field.name,
|
|
107
|
+
value: field.state.value,
|
|
108
|
+
onBlur: field.handleBlur,
|
|
109
|
+
onChange: (e)=>field.handleChange(e.currentTarget.value),
|
|
110
|
+
error: field.state.meta.errors.length > 0,
|
|
111
|
+
errorText: firstError(field.state.meta.errors),
|
|
112
|
+
autoComplete: "current-password",
|
|
113
|
+
required: true
|
|
114
|
+
})
|
|
115
|
+
}),
|
|
116
|
+
/*#__PURE__*/ jsx(form.Field, {
|
|
117
|
+
name: "newPassword",
|
|
118
|
+
children: (field)=>/*#__PURE__*/ jsx(InputPassword, {
|
|
119
|
+
label: "New password",
|
|
120
|
+
id: "newPassword",
|
|
121
|
+
name: field.name,
|
|
122
|
+
value: field.state.value,
|
|
123
|
+
onBlur: field.handleBlur,
|
|
124
|
+
onChange: (e)=>field.handleChange(e.currentTarget.value),
|
|
125
|
+
error: field.state.meta.errors.length > 0,
|
|
126
|
+
errorText: firstError(field.state.meta.errors),
|
|
127
|
+
autoComplete: "new-password",
|
|
128
|
+
required: true
|
|
129
|
+
})
|
|
130
|
+
}),
|
|
131
|
+
/*#__PURE__*/ jsx(form.Field, {
|
|
132
|
+
name: "confirm",
|
|
133
|
+
children: (field)=>/*#__PURE__*/ jsx(InputPassword, {
|
|
134
|
+
label: "Confirm new password",
|
|
135
|
+
id: "confirm",
|
|
136
|
+
name: field.name,
|
|
137
|
+
value: field.state.value,
|
|
138
|
+
onBlur: field.handleBlur,
|
|
139
|
+
onChange: (e)=>field.handleChange(e.currentTarget.value),
|
|
140
|
+
error: field.state.meta.errors.length > 0,
|
|
141
|
+
errorText: firstError(field.state.meta.errors),
|
|
142
|
+
autoComplete: "new-password",
|
|
143
|
+
required: true
|
|
144
|
+
})
|
|
145
|
+
}),
|
|
146
|
+
/*#__PURE__*/ jsxs("div", {
|
|
147
|
+
className: classnames('byline-account-change-password-actions', change_password_module.actions),
|
|
148
|
+
children: [
|
|
149
|
+
/*#__PURE__*/ jsx(Button, {
|
|
150
|
+
type: "button",
|
|
151
|
+
intent: "secondary",
|
|
152
|
+
size: "sm",
|
|
153
|
+
onClick: onClose,
|
|
154
|
+
className: classnames('byline-account-change-password-action', change_password_module.action),
|
|
155
|
+
children: successMessage ? 'Close' : 'Cancel'
|
|
156
|
+
}),
|
|
157
|
+
/*#__PURE__*/ jsx(form.Subscribe, {
|
|
158
|
+
selector: (state)=>({
|
|
159
|
+
canSubmit: state.canSubmit,
|
|
160
|
+
isSubmitting: state.isSubmitting,
|
|
161
|
+
isDirty: state.isDirty
|
|
162
|
+
}),
|
|
163
|
+
children: ({ canSubmit, isSubmitting })=>/*#__PURE__*/ jsx(Button, {
|
|
164
|
+
size: "sm",
|
|
165
|
+
intent: "primary",
|
|
166
|
+
type: "submit",
|
|
167
|
+
disabled: !canSubmit || isSubmitting,
|
|
168
|
+
className: classnames('byline-account-change-password-action', change_password_module.action),
|
|
169
|
+
children: true === isSubmitting ? /*#__PURE__*/ jsx(LoaderEllipsis, {
|
|
170
|
+
size: 42
|
|
171
|
+
}) : 'Save'
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
]
|
|
175
|
+
})
|
|
176
|
+
]
|
|
177
|
+
})
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
function firstError(errors) {
|
|
181
|
+
for (const err of errors){
|
|
182
|
+
if ('string' == typeof err) return err;
|
|
183
|
+
if (err && 'object' == typeof err && 'message' in err) {
|
|
184
|
+
const msg = err.message;
|
|
185
|
+
if ('string' == typeof msg) return msg;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function getErrorCode(err) {
|
|
190
|
+
return 'string' == typeof err?.code ? err.code : null;
|
|
191
|
+
}
|
|
192
|
+
export { ChangeAccountPassword };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
:is(.wrap-S1VOJs, .byline-account-change-password-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-W_yW2Y, .byline-account-change-password-form) {
|
|
10
|
+
gap: var(--spacing-16);
|
|
11
|
+
padding-top: var(--spacing-8);
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
display: flex;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:is(.actions-vW3jby, .byline-account-change-password-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-DnlRqk, .byline-account-change-password-action) {
|
|
25
|
+
min-width: 4rem;
|
|
26
|
+
}
|
|
27
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
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
|
+
* Self-service account container.
|
|
10
|
+
*
|
|
11
|
+
* Same drawer pattern as `admin-users/ui/container.tsx` but
|
|
12
|
+
* narrower: only Profile and Password sections (no Roles, no
|
|
13
|
+
* Delete) — those are admin-only actions on someone else, not
|
|
14
|
+
* self-service. Each card surfaces the read-only summary plus an
|
|
15
|
+
* "Edit" affordance that opens the matching drawer.
|
|
16
|
+
*
|
|
17
|
+
* Forms lift the fresh `AccountResponse` back into local state on
|
|
18
|
+
* success so the container's bumped `vid` is in hand for any
|
|
19
|
+
* subsequent edit without a refetch.
|
|
20
|
+
*
|
|
21
|
+
* Stable override handles: see `container.module.css`.
|
|
22
|
+
*/
|
|
23
|
+
import type React from 'react';
|
|
24
|
+
import type { AccountResponse } from '../index.js';
|
|
25
|
+
interface AccountSelfContainerProps {
|
|
26
|
+
account: AccountResponse;
|
|
27
|
+
}
|
|
28
|
+
export declare function AccountSelfContainer({ account }: AccountSelfContainerProps): React.JSX.Element;
|
|
29
|
+
export {};
|