@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
|
@@ -0,0 +1,121 @@
|
|
|
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
|
+
/**
|
|
10
|
+
* PHC (Password Hashing Competition) string format encode / decode for argon2id.
|
|
11
|
+
*
|
|
12
|
+
* Format:
|
|
13
|
+
* $argon2id$v=<ver>$m=<mem>,t=<iter>,p=<para>$<saltB64>$<hashB64>
|
|
14
|
+
*
|
|
15
|
+
* Where `saltB64` and `hashB64` use the PHC "B64" alphabet — standard base64
|
|
16
|
+
* without trailing `=` padding. Matches the wire format produced by
|
|
17
|
+
* `@node-rs/argon2` and `argon2-cffi`, so existing password column rows keep
|
|
18
|
+
* verifying after the cutover.
|
|
19
|
+
*
|
|
20
|
+
* Implemented against the Web-standard `btoa` / `atob` (available in Node ≥ 16,
|
|
21
|
+
* browsers, Workers, Deno, Bun) so this module has no Node-specific surface.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export type Argon2idPhc = {
|
|
25
|
+
/** Always `'argon2id'` for this codebase. */
|
|
26
|
+
algorithm: 'argon2id'
|
|
27
|
+
/** Argon2 version number — `0x13` (decimal 19) since RFC 9106. */
|
|
28
|
+
version: number
|
|
29
|
+
/** Memory cost in KiB. */
|
|
30
|
+
memoryCost: number
|
|
31
|
+
/** Iterations. */
|
|
32
|
+
timeCost: number
|
|
33
|
+
/** Parallelism (lanes). */
|
|
34
|
+
parallelism: number
|
|
35
|
+
/** Raw salt bytes. */
|
|
36
|
+
salt: Uint8Array
|
|
37
|
+
/** Raw derived-key bytes. */
|
|
38
|
+
hash: Uint8Array
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function bytesToB64NoPad(bytes: Uint8Array): string {
|
|
42
|
+
let bin = ''
|
|
43
|
+
for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i] as number)
|
|
44
|
+
return btoa(bin).replace(/=+$/, '')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function b64NoPadToBytes(b64: string): Uint8Array {
|
|
48
|
+
const padded = b64 + '='.repeat((4 - (b64.length % 4)) % 4)
|
|
49
|
+
const bin = atob(padded)
|
|
50
|
+
const out = new Uint8Array(bin.length)
|
|
51
|
+
for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i)
|
|
52
|
+
return out
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function encodeArgon2idPhc(phc: Argon2idPhc): string {
|
|
56
|
+
return (
|
|
57
|
+
`$${phc.algorithm}` +
|
|
58
|
+
`$v=${phc.version}` +
|
|
59
|
+
`$m=${phc.memoryCost},t=${phc.timeCost},p=${phc.parallelism}` +
|
|
60
|
+
`$${bytesToB64NoPad(phc.salt)}` +
|
|
61
|
+
`$${bytesToB64NoPad(phc.hash)}`
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function decodeArgon2idPhc(s: string): Argon2idPhc {
|
|
66
|
+
// Leading `$` produces an empty first segment, so a valid argon2id PHC string
|
|
67
|
+
// splits into exactly 6 parts: ['', algo, 'v=…', 'm=…,t=…,p=…', salt, hash].
|
|
68
|
+
const parts = s.split('$') as (string | undefined)[]
|
|
69
|
+
if (parts.length !== 6 || parts[0] !== '') {
|
|
70
|
+
throw new Error('decodeArgon2idPhc: malformed PHC string')
|
|
71
|
+
}
|
|
72
|
+
const algorithm = parts[1] ?? ''
|
|
73
|
+
const versionField = parts[2] ?? ''
|
|
74
|
+
const paramsField = parts[3] ?? ''
|
|
75
|
+
const saltB64 = parts[4] ?? ''
|
|
76
|
+
const hashB64 = parts[5] ?? ''
|
|
77
|
+
if (algorithm !== 'argon2id') {
|
|
78
|
+
throw new Error(`decodeArgon2idPhc: unsupported algorithm "${algorithm}"`)
|
|
79
|
+
}
|
|
80
|
+
if (!versionField.startsWith('v=')) {
|
|
81
|
+
throw new Error('decodeArgon2idPhc: missing version field')
|
|
82
|
+
}
|
|
83
|
+
const version = Number.parseInt(versionField.slice(2), 10)
|
|
84
|
+
if (!Number.isInteger(version)) {
|
|
85
|
+
throw new Error(`decodeArgon2idPhc: invalid version "${versionField}"`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const params: Partial<Record<'m' | 't' | 'p', number>> = {}
|
|
89
|
+
for (const kv of paramsField.split(',')) {
|
|
90
|
+
const eq = kv.indexOf('=')
|
|
91
|
+
if (eq <= 0) throw new Error(`decodeArgon2idPhc: malformed param "${kv}"`)
|
|
92
|
+
const k = kv.slice(0, eq)
|
|
93
|
+
const v = Number.parseInt(kv.slice(eq + 1), 10)
|
|
94
|
+
if (!Number.isInteger(v)) throw new Error(`decodeArgon2idPhc: malformed param value "${kv}"`)
|
|
95
|
+
if (k === 'm' || k === 't' || k === 'p') params[k] = v
|
|
96
|
+
}
|
|
97
|
+
if (params.m === undefined || params.t === undefined || params.p === undefined) {
|
|
98
|
+
throw new Error('decodeArgon2idPhc: missing required m/t/p params')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
algorithm: 'argon2id',
|
|
103
|
+
version,
|
|
104
|
+
memoryCost: params.m,
|
|
105
|
+
timeCost: params.t,
|
|
106
|
+
parallelism: params.p,
|
|
107
|
+
salt: b64NoPadToBytes(saltB64),
|
|
108
|
+
hash: b64NoPadToBytes(hashB64),
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Constant-time byte comparison. Returns `true` only if both arrays have the
|
|
114
|
+
* same length and every byte matches. Intended for hash verification.
|
|
115
|
+
*/
|
|
116
|
+
export function timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean {
|
|
117
|
+
if (a.length !== b.length) return false
|
|
118
|
+
let diff = 0
|
|
119
|
+
for (let i = 0; i < a.length; i++) diff |= (a[i] as number) ^ (b[i] as number)
|
|
120
|
+
return diff === 0
|
|
121
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
/**
|
|
10
|
+
* `RefreshTokensRepository` — the persistence contract for the
|
|
11
|
+
* `byline_admin_refresh_tokens` table.
|
|
12
|
+
*
|
|
13
|
+
* Lives under `modules/auth` rather than at the package root because this
|
|
14
|
+
* table exists to serve the built-in JWT session provider — a third-party
|
|
15
|
+
* session provider (Lucia, WorkOS, Clerk) would not use it. `token_hash`
|
|
16
|
+
* stores the SHA-256 of the plaintext refresh token; the plaintext leaves
|
|
17
|
+
* the server exactly once, when it is issued to the caller.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export interface RefreshTokenRow {
|
|
21
|
+
id: string
|
|
22
|
+
admin_user_id: string
|
|
23
|
+
token_hash: string
|
|
24
|
+
issued_at: Date
|
|
25
|
+
expires_at: Date
|
|
26
|
+
revoked_at: Date | null
|
|
27
|
+
rotated_to_id: string | null
|
|
28
|
+
last_used_at: Date | null
|
|
29
|
+
user_agent: string | null
|
|
30
|
+
ip: string | null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface IssueRefreshTokenInput {
|
|
34
|
+
id: string
|
|
35
|
+
admin_user_id: string
|
|
36
|
+
token_hash: string
|
|
37
|
+
expires_at: Date
|
|
38
|
+
user_agent?: string | null
|
|
39
|
+
ip?: string | null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface RefreshTokensRepository {
|
|
43
|
+
/** Insert a new refresh-token row. `id` is supplied by the caller (UUIDv7). */
|
|
44
|
+
issue(input: IssueRefreshTokenInput): Promise<RefreshTokenRow>
|
|
45
|
+
findByHash(tokenHash: string): Promise<RefreshTokenRow | null>
|
|
46
|
+
findById(id: string): Promise<RefreshTokenRow | null>
|
|
47
|
+
/** Stamp `last_used_at` for observability. */
|
|
48
|
+
touch(id: string, at?: Date): Promise<void>
|
|
49
|
+
/**
|
|
50
|
+
* Atomically revoke `oldId` and set its `rotated_to_id` to `newId`.
|
|
51
|
+
* Caller is responsible for inserting the new row (via `issue`) before
|
|
52
|
+
* calling this — ordering is a contract.
|
|
53
|
+
*/
|
|
54
|
+
markRotated(oldId: string, newId: string, at?: Date): Promise<void>
|
|
55
|
+
/** Revoke a single token. Idempotent. */
|
|
56
|
+
revoke(id: string, at?: Date): Promise<void>
|
|
57
|
+
/**
|
|
58
|
+
* Walk the rotation chain starting at `startId` and revoke every token
|
|
59
|
+
* in it. Called when a rotated token is replayed — indicates the chain
|
|
60
|
+
* has been compromised and every descendant is suspect. Returns the
|
|
61
|
+
* number of rows touched.
|
|
62
|
+
*/
|
|
63
|
+
revokeChain(startId: string, at?: Date): Promise<number>
|
|
64
|
+
/** Revoke every non-revoked token for a user. Used on password change / sign-out everywhere. */
|
|
65
|
+
revokeAllForUser(adminUserId: string, at?: Date): Promise<number>
|
|
66
|
+
/** Remove rows whose `expires_at` is in the past. Housekeeping. */
|
|
67
|
+
purgeExpired(now?: Date): Promise<number>
|
|
68
|
+
/** All non-revoked tokens for a user. Primarily for tests. */
|
|
69
|
+
listActiveForUser(adminUserId: string): Promise<RefreshTokenRow[]>
|
|
70
|
+
/** All tokens (including revoked) for a user. Primarily for tests and debugging. */
|
|
71
|
+
listAllForUser(adminUserId: string): Promise<RefreshTokenRow[]>
|
|
72
|
+
/** All tokens descended from `startId` via the rotation chain. Utility for tests. */
|
|
73
|
+
listRotationChain(startId: string): Promise<RefreshTokenRow[]>
|
|
74
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
import { AdminAuth } from '@byline/auth'
|
|
10
|
+
|
|
11
|
+
import type { AdminStore } from '../../store.js'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Build an `AdminAuth` from a user id by reading the admin-users row and
|
|
15
|
+
* collecting the distinct abilities granted through every role the user
|
|
16
|
+
* holds.
|
|
17
|
+
*
|
|
18
|
+
* Returns `null` when the user does not exist or is not enabled — callers
|
|
19
|
+
* interpret a null result as "no actor, sign-in refused". The enablement
|
|
20
|
+
* check lives here (rather than in the session provider) so that any code
|
|
21
|
+
* path resolving an actor from a stored user id — sign-in, token refresh,
|
|
22
|
+
* seeded super-admin context — applies the same gate.
|
|
23
|
+
*
|
|
24
|
+
* Consumes the admin-users and admin-permissions repositories through the
|
|
25
|
+
* `AdminStore` bundle; adapter-agnostic.
|
|
26
|
+
*/
|
|
27
|
+
export async function resolveActor(
|
|
28
|
+
store: AdminStore,
|
|
29
|
+
adminUserId: string
|
|
30
|
+
): Promise<AdminAuth | null> {
|
|
31
|
+
const user = await store.adminUsers.getById(adminUserId)
|
|
32
|
+
if (!user) return null
|
|
33
|
+
if (!user.is_enabled) return null
|
|
34
|
+
|
|
35
|
+
const abilities = await store.adminPermissions.listAbilitiesForUser(adminUserId)
|
|
36
|
+
|
|
37
|
+
return new AdminAuth({
|
|
38
|
+
id: user.id,
|
|
39
|
+
abilities,
|
|
40
|
+
isSuperAdmin: user.is_super_admin,
|
|
41
|
+
})
|
|
42
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
import { createContext, type ReactNode, useContext } from 'react'
|
|
10
|
+
|
|
11
|
+
import type { BylineAdminServices } from './admin-services-types.js'
|
|
12
|
+
|
|
13
|
+
export type {
|
|
14
|
+
AdminServiceCall,
|
|
15
|
+
BylineAdminServices,
|
|
16
|
+
ChangeAccountPasswordInput,
|
|
17
|
+
CreateAdminRoleInput,
|
|
18
|
+
CreateAdminUserInput,
|
|
19
|
+
SetAdminUserPasswordInput,
|
|
20
|
+
SetRoleAbilitiesInput,
|
|
21
|
+
SetUserRolesInput,
|
|
22
|
+
SignInInput,
|
|
23
|
+
SignInResult,
|
|
24
|
+
UpdateAccountInput,
|
|
25
|
+
UpdateAdminRoleInput,
|
|
26
|
+
UpdateAdminUserInput,
|
|
27
|
+
WhoHasAbilityInput,
|
|
28
|
+
} from './admin-services-types.js'
|
|
29
|
+
|
|
30
|
+
const AdminServicesContext = createContext<BylineAdminServices | null>(null)
|
|
31
|
+
|
|
32
|
+
interface BylineAdminServicesProviderProps {
|
|
33
|
+
services: BylineAdminServices
|
|
34
|
+
children: ReactNode
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const BylineAdminServicesProvider = ({
|
|
38
|
+
services,
|
|
39
|
+
children,
|
|
40
|
+
}: BylineAdminServicesProviderProps) => (
|
|
41
|
+
<AdminServicesContext.Provider value={services}>{children}</AdminServicesContext.Provider>
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
export const useBylineAdminServices = (): BylineAdminServices => {
|
|
45
|
+
const ctx = useContext(AdminServicesContext)
|
|
46
|
+
if (!ctx) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
'@byline/admin: BylineAdminServicesProvider missing. Wrap your admin tree with <BylineAdminServicesProvider services={…} />.'
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
return ctx
|
|
52
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
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
|
+
/**
|
|
10
|
+
* Framework-neutral function contracts that admin UI components in
|
|
11
|
+
* `@byline/ui` need from the host application. The host wires concrete
|
|
12
|
+
* implementations via `BylineAdminServicesProvider` — typically thin
|
|
13
|
+
* adapters around TanStack Start server functions, Next.js server
|
|
14
|
+
* actions, or any other RPC-style transport.
|
|
15
|
+
*
|
|
16
|
+
* The call shape `(args: { data: TInput }) => Promise<TOutput>` mirrors
|
|
17
|
+
* TanStack Start's `createServerFn().handler()` calling convention so a
|
|
18
|
+
* webapp host can pass its server fns through as-is. Other transports
|
|
19
|
+
* just need a tiny adapter.
|
|
20
|
+
*
|
|
21
|
+
* Scope: Phase 2.1 covers the framework-neutral admin UI components
|
|
22
|
+
* only — the 15 forms, modals, and inner widgets that don't touch
|
|
23
|
+
* TanStack Router. Page containers (list/edit/delete pages) keep using
|
|
24
|
+
* server fns directly today and move into `@byline/host-tanstack-start`
|
|
25
|
+
* in Phase 3 along with the route factories.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import type {
|
|
29
|
+
AccountResponse,
|
|
30
|
+
ChangeAccountPasswordRequest,
|
|
31
|
+
UpdateAccountRequest,
|
|
32
|
+
} from '../modules/admin-account/index.js'
|
|
33
|
+
import type {
|
|
34
|
+
SetRoleAbilitiesResponse,
|
|
35
|
+
WhoHasAbilityResponse,
|
|
36
|
+
} from '../modules/admin-permissions/index.js'
|
|
37
|
+
import type { AdminRoleResponse, UserRolesResponse } from '../modules/admin-roles/index.js'
|
|
38
|
+
import type { AdminUserResponse } from '../modules/admin-users/index.js'
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The TanStack Start `createServerFn(...).handler(...)` calling shape:
|
|
42
|
+
* `fn({ data: input }) → Promise<output>`. Hosts using a different
|
|
43
|
+
* transport supply small adapters that match this shape.
|
|
44
|
+
*/
|
|
45
|
+
export type AdminServiceCall<TInput, TOutput> = (args: { data: TInput }) => Promise<TOutput>
|
|
46
|
+
|
|
47
|
+
// --- Auth -----------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
export interface SignInInput {
|
|
50
|
+
email: string
|
|
51
|
+
password: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The admin UI's sign-in form does not consume the `SignInResult`
|
|
56
|
+
* payload directly — on success it navigates via `window.location`. The
|
|
57
|
+
* shape is left as `unknown` here so each host's session provider can
|
|
58
|
+
* supply whatever envelope it produces without forcing a public type.
|
|
59
|
+
*/
|
|
60
|
+
export type SignInResult = unknown
|
|
61
|
+
|
|
62
|
+
// --- Account self-service -------------------------------------------------
|
|
63
|
+
|
|
64
|
+
/** Same shape as `UpdateAccountRequest` from `@byline/admin/admin-account`. */
|
|
65
|
+
export type UpdateAccountInput = UpdateAccountRequest
|
|
66
|
+
|
|
67
|
+
/** Same shape as `ChangeAccountPasswordRequest` from `@byline/admin/admin-account`. */
|
|
68
|
+
export type ChangeAccountPasswordInput = ChangeAccountPasswordRequest
|
|
69
|
+
|
|
70
|
+
// --- Admin users ----------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
export interface CreateAdminUserInput {
|
|
73
|
+
email: string
|
|
74
|
+
password: string
|
|
75
|
+
given_name?: string | null
|
|
76
|
+
family_name?: string | null
|
|
77
|
+
username?: string | null
|
|
78
|
+
is_super_admin: boolean
|
|
79
|
+
is_enabled: boolean
|
|
80
|
+
is_email_verified: boolean
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface UpdateAdminUserInput {
|
|
84
|
+
id: string
|
|
85
|
+
vid: number
|
|
86
|
+
patch: {
|
|
87
|
+
email?: string
|
|
88
|
+
given_name?: string | null
|
|
89
|
+
family_name?: string | null
|
|
90
|
+
username?: string | null
|
|
91
|
+
is_super_admin?: boolean
|
|
92
|
+
is_enabled?: boolean
|
|
93
|
+
is_email_verified?: boolean
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface SetAdminUserPasswordInput {
|
|
98
|
+
id: string
|
|
99
|
+
vid: number
|
|
100
|
+
password: string
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface SetUserRolesInput {
|
|
104
|
+
userId: string
|
|
105
|
+
roleIds: string[]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// --- Admin roles ----------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
export interface CreateAdminRoleInput {
|
|
111
|
+
name: string
|
|
112
|
+
machine_name: string
|
|
113
|
+
description: string | null
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface UpdateAdminRoleInput {
|
|
117
|
+
id: string
|
|
118
|
+
vid: number
|
|
119
|
+
patch: {
|
|
120
|
+
name?: string
|
|
121
|
+
description?: string | null
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// --- Permissions ----------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
export interface SetRoleAbilitiesInput {
|
|
128
|
+
id: string
|
|
129
|
+
abilities: string[]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface WhoHasAbilityInput {
|
|
133
|
+
ability: string
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// --- Service contract -----------------------------------------------------
|
|
137
|
+
|
|
138
|
+
export interface BylineAdminServices {
|
|
139
|
+
// Auth
|
|
140
|
+
adminSignIn: AdminServiceCall<SignInInput, SignInResult>
|
|
141
|
+
|
|
142
|
+
// Account self-service
|
|
143
|
+
updateAccount: AdminServiceCall<UpdateAccountInput, AccountResponse>
|
|
144
|
+
changeAccountPassword: AdminServiceCall<ChangeAccountPasswordInput, AccountResponse>
|
|
145
|
+
|
|
146
|
+
// Admin user writes (page-container reads stay in the host for now)
|
|
147
|
+
createAdminUser: AdminServiceCall<CreateAdminUserInput, AdminUserResponse>
|
|
148
|
+
updateAdminUser: AdminServiceCall<UpdateAdminUserInput, AdminUserResponse>
|
|
149
|
+
setAdminUserPassword: AdminServiceCall<SetAdminUserPasswordInput, AdminUserResponse>
|
|
150
|
+
setUserRoles: AdminServiceCall<SetUserRolesInput, UserRolesResponse>
|
|
151
|
+
|
|
152
|
+
// Admin role writes
|
|
153
|
+
createAdminRole: AdminServiceCall<CreateAdminRoleInput, AdminRoleResponse>
|
|
154
|
+
updateAdminRole: AdminServiceCall<UpdateAdminRoleInput, AdminRoleResponse>
|
|
155
|
+
|
|
156
|
+
// Permissions
|
|
157
|
+
setRoleAbilities: AdminServiceCall<SetRoleAbilitiesInput, SetRoleAbilitiesResponse>
|
|
158
|
+
whoHasAbility: AdminServiceCall<WhoHasAbilityInput, WhoHasAbilityResponse>
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Diff helper. Loads a specific historical version of a document so
|
|
162
|
+
* the diff modal can compare it against the current version. Returns
|
|
163
|
+
* the same shape as the regular document loader — the diff modal
|
|
164
|
+
* consumes only `doc.fields` (or strips known meta keys when an
|
|
165
|
+
* older flat-shape doc is encountered).
|
|
166
|
+
*
|
|
167
|
+
* Positional-args shape rather than `{ data }` because this helper
|
|
168
|
+
* predates the contract and is consumed only by `DiffModal`. Hosts
|
|
169
|
+
* adapt their server fn into this call signature.
|
|
170
|
+
*/
|
|
171
|
+
getCollectionDocumentVersion: (
|
|
172
|
+
collection: string,
|
|
173
|
+
documentId: string,
|
|
174
|
+
versionId: string,
|
|
175
|
+
locale: string | undefined
|
|
176
|
+
) => Promise<Record<string, unknown>>
|
|
177
|
+
}
|
package/src/store.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
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
|
+
import type { AdminPermissionsRepository } from './modules/admin-permissions/repository.js'
|
|
10
|
+
import type { AdminRolesRepository } from './modules/admin-roles/repository.js'
|
|
11
|
+
import type { AdminUsersRepository } from './modules/admin-users/repository.js'
|
|
12
|
+
import type { RefreshTokensRepository } from './modules/auth/refresh-tokens-repository.js'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The bundle of repositories that `@byline/admin` needs from the DB
|
|
16
|
+
* adapter. A DB adapter package (`@byline/db-postgres`, a future
|
|
17
|
+
* `@byline/db-mysql`) is expected to expose a factory — conventionally
|
|
18
|
+
* `createAdminStore(db)` — that returns an `AdminStore` wired against
|
|
19
|
+
* its concrete schema. The bundle is passed to the built-in
|
|
20
|
+
* `JwtSessionProvider`, to `seedSuperAdmin`, and (later) to admin-user
|
|
21
|
+
* and admin-role commands.
|
|
22
|
+
*
|
|
23
|
+
* Keeping the four repositories together as a single argument avoids
|
|
24
|
+
* exploding constructor signatures and makes "needs admin DB access" a
|
|
25
|
+
* single, recognisable type.
|
|
26
|
+
*/
|
|
27
|
+
export interface AdminStore {
|
|
28
|
+
adminUsers: AdminUsersRepository
|
|
29
|
+
adminRoles: AdminRolesRepository
|
|
30
|
+
adminPermissions: AdminPermissionsRepository
|
|
31
|
+
refreshTokens: RefreshTokensRepository
|
|
32
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Paul Miller (https://paulmillr.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# noble-argon2 (vendored)
|
|
2
|
+
|
|
3
|
+
Vendored subset of [`@noble/hashes`](https://github.com/paulmillr/noble-hashes)
|
|
4
|
+
sufficient to compute argon2id password hashes. Vendored — rather than depended
|
|
5
|
+
on via npm — to remove the npm install-time supply-chain risk for the password
|
|
6
|
+
hashing path.
|
|
7
|
+
|
|
8
|
+
The MIT license under which we received this code is included verbatim as
|
|
9
|
+
`./LICENSE`.
|
|
10
|
+
|
|
11
|
+
## Why vendored
|
|
12
|
+
|
|
13
|
+
`@byline/admin` previously depended on `@node-rs/argon2`, a Rust binding that
|
|
14
|
+
requires a per-platform native binary. That blocks deployment to non-Node
|
|
15
|
+
runtimes (Workers, Deno, Bun without Node-API shims) and adds a transitive
|
|
16
|
+
install-time supply-chain surface. `@noble/hashes` is pure JS, runs in any
|
|
17
|
+
runtime with WebAssembly-free standard JS, and is explicitly designed by its
|
|
18
|
+
author to be auditable and vendorable.
|
|
19
|
+
|
|
20
|
+
We copy only the modules required for argon2id, in full, with attribution.
|
|
21
|
+
Other parts of `@noble/hashes` (sha2, sha3, scrypt, …) are not pulled in.
|
|
22
|
+
|
|
23
|
+
## Provenance
|
|
24
|
+
|
|
25
|
+
| Field | Value |
|
|
26
|
+
| ------------------------ | ----------------------------------------------------------- |
|
|
27
|
+
| Upstream repo | https://github.com/paulmillr/noble-hashes |
|
|
28
|
+
| Upstream release tag | `2.2.0` |
|
|
29
|
+
| Upstream commit | `81983c2fffac48aa69dabc260b4192ad597d2734` |
|
|
30
|
+
| Upstream tag date | 2026-04-11 |
|
|
31
|
+
| Upstream license | MIT (see `./LICENSE`) |
|
|
32
|
+
| Files copied | `argon2.ts`, `blake2.ts`, `_blake.ts`, `_u64.ts`, `_md.ts`, `utils.ts` |
|
|
33
|
+
|
|
34
|
+
The files were fetched from
|
|
35
|
+
`https://raw.githubusercontent.com/paulmillr/noble-hashes/<commit>/src/<file>`.
|
|
36
|
+
|
|
37
|
+
## Local modifications
|
|
38
|
+
|
|
39
|
+
Only two mechanical edits are applied to the upstream sources:
|
|
40
|
+
|
|
41
|
+
1. **Import-extension rewrite.** Relative import specifiers are rewritten from
|
|
42
|
+
`'./<name>.ts'` to `'./<name>.js'`. Required by `@byline/admin`'s
|
|
43
|
+
`module: NodeNext` TypeScript configuration, which emits ES modules and
|
|
44
|
+
resolves imports against the emitted `.js` paths.
|
|
45
|
+
2. **`// @ts-nocheck` header.** A single-line `// @ts-nocheck — vendored from
|
|
46
|
+
noble-hashes; see ./README.md` is prepended to every vendored `.ts` file.
|
|
47
|
+
Required because this project enables `noUncheckedIndexedAccess` and a few
|
|
48
|
+
other strict-mode flags that noble-hashes does not. The vendored algorithm
|
|
49
|
+
code is exercised by the upstream test suite at noble's tsconfig settings,
|
|
50
|
+
and additionally by `tests/noble-argon2-vectors.test.node.ts` against
|
|
51
|
+
published RFC 9106 / P-H-C reference vectors, so suppressing project lint
|
|
52
|
+
inside the vendored copy does not weaken the assurance we have over the
|
|
53
|
+
correctness of these files.
|
|
54
|
+
|
|
55
|
+
No algorithm code, no constants, and no exported APIs have been changed.
|
|
56
|
+
|
|
57
|
+
To re-verify, fetch each file at the commit pinned above and run
|
|
58
|
+
`diff <upstream> <vendored>` — every diff line should be one of:
|
|
59
|
+
|
|
60
|
+
- A single-line `// @ts-nocheck` header at the top of the file
|
|
61
|
+
- `./_blake.ts` → `./_blake.js`
|
|
62
|
+
- `./_md.ts` → `./_md.js`
|
|
63
|
+
- `./_u64.ts` → `./_u64.js`
|
|
64
|
+
- `./blake2.ts` → `./blake2.js`
|
|
65
|
+
- `./utils.ts` → `./utils.js`
|
|
66
|
+
|
|
67
|
+
## Surface area used
|
|
68
|
+
|
|
69
|
+
`packages/admin/src/modules/auth/password.ts` consumes only `argon2id` and
|
|
70
|
+
`argon2idAsync` from `./argon2.js`. The other exports (`argon2d`, `argon2i`,
|
|
71
|
+
their async variants, the BLAKE2s class, miscellaneous utility helpers) are
|
|
72
|
+
present because they live in the same source files; bundlers eliminate them as
|
|
73
|
+
dead code.
|
|
74
|
+
|
|
75
|
+
The fidelity of this vendored copy is checked by
|
|
76
|
+
`packages/admin/tests/noble-argon2-vectors.test.node.ts`, which runs published
|
|
77
|
+
RFC 9106 / noble-hashes argon2id test vectors against this code.
|
|
78
|
+
|
|
79
|
+
## Re-syncing to a newer upstream commit
|
|
80
|
+
|
|
81
|
+
1. Pick the new release tag and resolve it to a commit SHA.
|
|
82
|
+
2. For each file in this directory, replace its contents with the upstream
|
|
83
|
+
file at that commit.
|
|
84
|
+
3. Re-apply the `.ts` → `.js` import-extension change (a single sed pass:
|
|
85
|
+
`sed -i '' "s|from '\\./\\([_a-z0-9]*\\)\\.ts'|from './\\1.js'|g" *.ts`).
|
|
86
|
+
4. Update the commit, tag, and date in the table above.
|
|
87
|
+
5. Run `pnpm test` in `packages/admin/` to confirm the test vectors still pass.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// @ts-nocheck — vendored from noble-hashes; see ./README.md
|
|
2
|
+
/**
|
|
3
|
+
* Internal helpers for blake hash.
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { rotr, type TRet } from './utils.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Internal blake permutation table.
|
|
10
|
+
* Rows `0..9` serve BLAKE2s, rows `0..11` serve BLAKE2b with `10..11 = 0..1`, and Blake1 also
|
|
11
|
+
* reuses the later rows shown below. Blake1 expands rounds `10..15` as `SIGMA[i % 10]`, so rows
|
|
12
|
+
* `10..15` intentionally repeat rows `0..5` for the 14-round (256) and 16-round (512) variants.
|
|
13
|
+
*/
|
|
14
|
+
// prettier-ignore
|
|
15
|
+
export const BSIGMA: TRet<Uint8Array> = /* @__PURE__ */ Uint8Array.from([
|
|
16
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
17
|
+
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
|
|
18
|
+
11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
|
|
19
|
+
7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
|
|
20
|
+
9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
|
|
21
|
+
2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
|
|
22
|
+
12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11,
|
|
23
|
+
13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10,
|
|
24
|
+
6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5,
|
|
25
|
+
10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0,
|
|
26
|
+
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
|
27
|
+
14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3,
|
|
28
|
+
// Blake1, unused in others
|
|
29
|
+
11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4,
|
|
30
|
+
7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8,
|
|
31
|
+
9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13,
|
|
32
|
+
2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9,
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
// prettier-ignore
|
|
36
|
+
export type Num4 = { a: number; b: number; c: number; d: number; };
|
|
37
|
+
|
|
38
|
+
// 32-bit / BLAKE2s first half of G, with the fixed `(16, 12)` rotation pair.
|
|
39
|
+
// Parameter `x` is the RFC 7693 first-half message word, or Blake1's pre-mixed
|
|
40
|
+
// `m[sigma[r][2i]] ^ u[sigma[r][2i+1]]` addend in the 32-bit path.
|
|
41
|
+
export function G1s(a: number, b: number, c: number, d: number, x: number): Num4 {
|
|
42
|
+
a = (a + b + x) | 0;
|
|
43
|
+
d = rotr(d ^ a, 16);
|
|
44
|
+
c = (c + d) | 0;
|
|
45
|
+
b = rotr(b ^ c, 12);
|
|
46
|
+
return { a, b, c, d };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 32-bit / BLAKE2s second half of G.
|
|
50
|
+
// Parameter `x` is the RFC 7693 second-half (`y`) message word, or Blake1's pre-mixed
|
|
51
|
+
// `m[sigma[r][2i + 1]] ^ u[sigma[r][2i]]` addend in the 32-bit path.
|
|
52
|
+
export function G2s(a: number, b: number, c: number, d: number, x: number): Num4 {
|
|
53
|
+
a = (a + b + x) | 0;
|
|
54
|
+
d = rotr(d ^ a, 8);
|
|
55
|
+
c = (c + d) | 0;
|
|
56
|
+
b = rotr(b ^ c, 7);
|
|
57
|
+
return { a, b, c, d };
|
|
58
|
+
}
|