create-astram-app 0.11.1 → 0.12.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/index.js +98 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/template/frontend/_env.example +7 -0
- package/template/frontend/package.json +2 -2
- package/template/frontend/src/App.jsx +24 -0
- package/template/frontend/src/auth/AuthContext.jsx +73 -30
- package/template/frontend/src/auth/CaptchaWidget.jsx +108 -0
- package/template/frontend/src/auth/captchaProvider.js +23 -0
- package/template/frontend/src/auth/captchaProvider.test.mjs +44 -0
- package/template/frontend/src/auth/captchaRender.js +125 -0
- package/template/frontend/src/auth/captchaRender.test.mjs +182 -0
- package/template/frontend/src/auth/passwordVisibility.js +9 -0
- package/template/frontend/src/auth/passwordVisibility.test.mjs +12 -0
- package/template/frontend/src/auth/reenrollWording.js +29 -0
- package/template/frontend/src/auth/reenrollWording.test.mjs +23 -0
- package/template/frontend/src/auth/routeGate.js +10 -0
- package/template/frontend/src/auth/routeGate.test.mjs +22 -1
- package/template/frontend/src/auth/sessionFlow.js +80 -4
- package/template/frontend/src/auth/sessionFlow.test.mjs +212 -1
- package/template/frontend/src/auth/signInOptions.js +64 -0
- package/template/frontend/src/auth/signInOptions.test.mjs +94 -0
- package/template/frontend/src/auth/useSignInOptions.js +34 -0
- package/template/frontend/src/pages/ForgotPassword.jsx +49 -3
- package/template/frontend/src/pages/Login.jsx +54 -4
- package/template/frontend/src/pages/ResetPassword.jsx +83 -11
- package/template/frontend/src/pages/account/ReenrollPage.jsx +17 -11
- package/template/frontend/src/pages/account/TwoFactorPage.jsx +9 -6
- package/template/frontend/src/pages/audit/AuditPage.jsx +17 -3
- package/template/frontend/src/pages/audit/actorKind.js +17 -0
- package/template/frontend/src/pages/audit/actorKind.test.mjs +23 -0
- package/template/frontend/src/pages/companies/CompaniesPage.jsx +104 -4
- package/template/frontend/src/pages/companies/moveAction.js +61 -0
- package/template/frontend/src/pages/companies/moveAction.test.mjs +91 -0
- package/template/frontend/src/pages/org-structure/OrgStructurePage.jsx +408 -0
- package/template/frontend/src/pages/org-structure/orgStructure.js +140 -0
- package/template/frontend/src/pages/org-structure/orgStructure.test.mjs +199 -0
- package/template/frontend/src/pages/roles/RoleForm.jsx +32 -14
- package/template/frontend/src/pages/roles/RolesPage.jsx +167 -42
- package/template/frontend/src/pages/roles/roleRules.js +104 -0
- package/template/frontend/src/pages/roles/roleRules.test.mjs +178 -0
- package/template/frontend/src/pages/security/PolicyFormDialog.jsx +243 -0
- package/template/frontend/src/pages/security/SecuritySettingsPage.jsx +229 -0
- package/template/frontend/src/pages/security/securityPolicies.js +246 -0
- package/template/frontend/src/pages/security/securityPolicies.test.mjs +429 -0
- package/template/frontend/src/pages/users/MembershipCard.jsx +5 -2
- package/template/frontend/src/pages/users/PostingRow.jsx +13 -10
- package/template/frontend/src/pages/users/SignInActionDialog.jsx +98 -0
- package/template/frontend/src/pages/users/UserForm.jsx +65 -3
- package/template/frontend/src/pages/users/UsersPage.jsx +91 -3
- package/template/frontend/src/pages/users/loginName.js +108 -0
- package/template/frontend/src/pages/users/loginName.test.mjs +133 -0
- package/template/frontend/src/pages/users/signInAdmin.js +122 -0
- package/template/frontend/src/pages/users/signInAdmin.test.mjs +183 -0
- package/template/frontend/src/platform/httpClient.js +40 -28
- package/template/frontend/src/platform/httpClient.test.mjs +71 -0
- package/template/frontend/src/platform/shieldTransport.js +12 -12
- package/template/frontend/src/shell/AppShell.jsx +4 -0
- package/template/frontend/src/shell/GraceBanner.jsx +28 -0
- package/template/frontend/src/shell/graceDeadline.js +50 -0
- package/template/frontend/src/shell/graceDeadline.test.mjs +59 -0
- package/template/frontend/src/shell/nav.js +30 -1
- package/template/frontend/src/viteConfig.test.mjs +63 -0
- package/template/frontend/vite/captchaCsp.js +99 -0
- package/template/frontend/vite.config.js +14 -3
- package/template/server/_env.example +25 -0
- package/template/server/package.json +9 -6
- package/template/server/src/app.module.ts +17 -6
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* npx create-astram-app <name> # server/ only
|
|
6
6
|
* npx create-astram-app <name> --with-frontend # + frontend/ (identity UI)
|
|
7
|
+
* npx create-astram-app <name> --captcha turnstile # CAPTCHA provider in both .env.example files
|
|
7
8
|
*
|
|
8
9
|
* Emits a NEW consumer app directory that depends on the published, immutable
|
|
9
10
|
* framework packages (`@astram/core`, `@astram/guard`, `@astram/sdk`) via real
|
|
@@ -68,8 +69,49 @@ export function validateAppName(name) {
|
|
|
68
69
|
}
|
|
69
70
|
return null;
|
|
70
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* CAPTCHA providers the framework supports (server `CAPTCHA_PROVIDER`, frontend build
|
|
74
|
+
* `VITE_CAPTCHA_PROVIDER`; R7.6, D-10). `none` on the command line means no CAPTCHA.
|
|
75
|
+
*/
|
|
76
|
+
export const CAPTCHA_PROVIDERS = ['turnstile', 'recaptcha-v3', 'recaptcha-v2'];
|
|
77
|
+
const CAPTCHA_FLAG = '--captcha';
|
|
78
|
+
function isCaptchaProvider(value) {
|
|
79
|
+
return CAPTCHA_PROVIDERS.includes(value);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Read `--captcha <provider>` / `--captcha=<provider>` from argv. Absent or `none` ⇒ null
|
|
83
|
+
* (no CAPTCHA, the default). An unknown or missing value is an error.
|
|
84
|
+
*/
|
|
85
|
+
export function parseCaptchaProvider(argv) {
|
|
86
|
+
let value;
|
|
87
|
+
let seen = false;
|
|
88
|
+
argv.forEach((arg, i) => {
|
|
89
|
+
if (arg === CAPTCHA_FLAG) {
|
|
90
|
+
seen = true;
|
|
91
|
+
const next = argv[i + 1];
|
|
92
|
+
value = next !== undefined && !next.startsWith('--') ? next : undefined;
|
|
93
|
+
}
|
|
94
|
+
else if (arg.startsWith(`${CAPTCHA_FLAG}=`)) {
|
|
95
|
+
seen = true;
|
|
96
|
+
value = arg.slice(CAPTCHA_FLAG.length + 1);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
if (!seen)
|
|
100
|
+
return { provider: null };
|
|
101
|
+
if (value === undefined || value === '') {
|
|
102
|
+
return { error: `${CAPTCHA_FLAG} needs a value: ${CAPTCHA_PROVIDERS.join(', ')} or none` };
|
|
103
|
+
}
|
|
104
|
+
if (value === 'none')
|
|
105
|
+
return { provider: null };
|
|
106
|
+
if (!isCaptchaProvider(value)) {
|
|
107
|
+
return {
|
|
108
|
+
error: `unknown CAPTCHA provider "${value}"; use one of ${CAPTCHA_PROVIDERS.join(', ')} or none`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
return { provider: value };
|
|
112
|
+
}
|
|
71
113
|
const USAGE = [
|
|
72
|
-
'Usage: create-astram-app <name> [--with-frontend]',
|
|
114
|
+
'Usage: create-astram-app <name> [--with-frontend] [--captcha <provider>]',
|
|
73
115
|
'',
|
|
74
116
|
'Scaffolds a new Astram consumer app that depends on the published framework',
|
|
75
117
|
'(@astram/core, @astram/guard, @astram/sdk) and enforces deny-by-default from',
|
|
@@ -77,10 +119,15 @@ const USAGE = [
|
|
|
77
119
|
'',
|
|
78
120
|
' --with-frontend Also scaffold frontend/ (Vite/React identity UI).',
|
|
79
121
|
' Without this flag, only server/ is scaffolded.',
|
|
122
|
+
' --captcha <p> CAPTCHA provider for sign-in: turnstile, recaptcha-v3,',
|
|
123
|
+
' recaptcha-v2 or none (default). Writes the same value as',
|
|
124
|
+
' CAPTCHA_PROVIDER (server/.env.example) and',
|
|
125
|
+
' VITE_CAPTCHA_PROVIDER (frontend/.env.example).',
|
|
80
126
|
'',
|
|
81
127
|
'Example:',
|
|
82
128
|
' npx create-astram-app my-app',
|
|
83
129
|
' npx create-astram-app my-app --with-frontend',
|
|
130
|
+
' npx create-astram-app my-app --with-frontend --captcha turnstile',
|
|
84
131
|
].join('\n');
|
|
85
132
|
/**
|
|
86
133
|
* Copy a SINGLE template file `srcPath` → `destPath` (never a directory),
|
|
@@ -147,6 +194,28 @@ function isTextFile(fileName) {
|
|
|
147
194
|
* gated: `server/` is always emitted, `frontend/` only with `--with-frontend`.
|
|
148
195
|
*/
|
|
149
196
|
const TEMPLATE_SUBTREES = ['server', 'frontend'];
|
|
197
|
+
/**
|
|
198
|
+
* The one CAPTCHA answer lands in both env files, server `CAPTCHA_PROVIDER` and frontend
|
|
199
|
+
* `VITE_CAPTCHA_PROVIDER`, so the build's CSP and the server agree (D-10). Each file's commented
|
|
200
|
+
* template line is replaced by the set value; only files this run wrote are touched (never-clobber).
|
|
201
|
+
*/
|
|
202
|
+
const CAPTCHA_ENV_LINES = [
|
|
203
|
+
{ rel: 'server/.env.example', name: 'CAPTCHA_PROVIDER' },
|
|
204
|
+
{ rel: 'frontend/.env.example', name: 'VITE_CAPTCHA_PROVIDER' },
|
|
205
|
+
];
|
|
206
|
+
function writeCaptchaProvider(targetDir, report, provider) {
|
|
207
|
+
for (const { rel, name } of CAPTCHA_ENV_LINES) {
|
|
208
|
+
if (!report.written.includes(rel))
|
|
209
|
+
continue;
|
|
210
|
+
const file = join(targetDir, rel);
|
|
211
|
+
const text = readFileSync(file, 'utf8');
|
|
212
|
+
const line = new RegExp(`^# ${name}=.*$`, 'm');
|
|
213
|
+
if (!line.test(text)) {
|
|
214
|
+
throw new Error(`template ${rel} has no "# ${name}=" line to set`);
|
|
215
|
+
}
|
|
216
|
+
writeFileSync(file, text.replace(line, `${name}=${provider}`), 'utf8');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
150
219
|
/**
|
|
151
220
|
* Scaffold `appName` into `<cwd>/<appName>`. Returns the copy report + resolved
|
|
152
221
|
* target dir. Exported for tests (which pass an explicit `cwd`).
|
|
@@ -157,7 +226,11 @@ const TEMPLATE_SUBTREES = ['server', 'frontend'];
|
|
|
157
226
|
* `server/` and the app-root files (`.astram/guide/`, `CLAUDE.md`, `.gitignore`,
|
|
158
227
|
* `README.md`) are unconditional either way — unchanged from prior behavior.
|
|
159
228
|
*/
|
|
160
|
-
export function scaffold(appName, cwd = process.cwd(), withFrontend = false) {
|
|
229
|
+
export function scaffold(appName, cwd = process.cwd(), withFrontend = false, options = {}) {
|
|
230
|
+
const captchaProvider = options.captchaProvider ?? null;
|
|
231
|
+
if (captchaProvider !== null && !isCaptchaProvider(captchaProvider)) {
|
|
232
|
+
throw new Error(`unknown CAPTCHA provider "${String(captchaProvider)}"; use one of ${CAPTCHA_PROVIDERS.join(', ')}`);
|
|
233
|
+
}
|
|
161
234
|
const targetDir = resolve(cwd, appName);
|
|
162
235
|
const report = { written: [], skipped: [] };
|
|
163
236
|
if (existsSync(targetDir)) {
|
|
@@ -201,6 +274,9 @@ export function scaffold(appName, cwd = process.cwd(), withFrontend = false) {
|
|
|
201
274
|
if (withFrontend) {
|
|
202
275
|
copyTemplate(join(template, 'frontend'), join(targetDir, 'frontend'), appName, report, 'frontend');
|
|
203
276
|
}
|
|
277
|
+
if (captchaProvider !== null) {
|
|
278
|
+
writeCaptchaProvider(targetDir, report, captchaProvider);
|
|
279
|
+
}
|
|
204
280
|
return { targetDir, report };
|
|
205
281
|
}
|
|
206
282
|
/** Long-form boolean flags this CLI recognizes (anywhere in argv). */
|
|
@@ -212,12 +288,19 @@ const WITH_FRONTEND_FLAG = '--with-frontend';
|
|
|
212
288
|
* `create-astram-app my-app --with-frontend` both work).
|
|
213
289
|
*/
|
|
214
290
|
function parseAppName(argv) {
|
|
215
|
-
|
|
291
|
+
// Skip the value that follows a bare `--captcha` (`--captcha turnstile my-app`).
|
|
292
|
+
return argv.find((arg, i) => !arg.startsWith('--') && argv[i - 1] !== CAPTCHA_FLAG);
|
|
216
293
|
}
|
|
217
294
|
/** Entry point. Returns a process exit code (0 ok, non-zero on error). */
|
|
218
295
|
export function main(argv = process.argv.slice(2)) {
|
|
219
296
|
const name = parseAppName(argv);
|
|
220
297
|
const withFrontend = argv.includes(WITH_FRONTEND_FLAG);
|
|
298
|
+
const captcha = parseCaptchaProvider(argv);
|
|
299
|
+
if ('error' in captcha) {
|
|
300
|
+
console.error(`create-astram-app: ${captcha.error}\n`);
|
|
301
|
+
console.error(USAGE);
|
|
302
|
+
return 1;
|
|
303
|
+
}
|
|
221
304
|
const validationError = validateAppName(name);
|
|
222
305
|
if (validationError) {
|
|
223
306
|
console.error(`create-astram-app: ${validationError}\n`);
|
|
@@ -227,7 +310,9 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
227
310
|
const appName = name.trim();
|
|
228
311
|
let report;
|
|
229
312
|
try {
|
|
230
|
-
({ report } = scaffold(appName, process.cwd(), withFrontend
|
|
313
|
+
({ report } = scaffold(appName, process.cwd(), withFrontend, {
|
|
314
|
+
captchaProvider: captcha.provider,
|
|
315
|
+
}));
|
|
231
316
|
}
|
|
232
317
|
catch (err) {
|
|
233
318
|
console.error(`create-astram-app: ${err.message}`);
|
|
@@ -260,6 +345,15 @@ export function main(argv = process.argv.slice(2)) {
|
|
|
260
345
|
console.log(' server/src/app.module.ts (see its comment block). Before production, read the');
|
|
261
346
|
console.log(' README "Production requirements" (emailSender, link URLs, NODE_ENV, TRUST_PROXY,');
|
|
262
347
|
console.log(' migrations).');
|
|
348
|
+
if (captcha.provider !== null) {
|
|
349
|
+
console.log(`\n CAPTCHA: ${captcha.provider}. CAPTCHA_PROVIDER (server/.env.example) and`);
|
|
350
|
+
console.log(' VITE_CAPTCHA_PROVIDER (frontend/.env.example) are set to the same value; copy');
|
|
351
|
+
console.log(' them to .env, fill CAPTCHA_SITE_KEY, CAPTCHA_SECRET (a secret-ref:) and');
|
|
352
|
+
console.log(" CAPTCHA_EXPECTED_HOSTNAMES, and pass ShieldModule.forRoot({ captcha: 'env' }).");
|
|
353
|
+
if (!withFrontend) {
|
|
354
|
+
console.log(` Adding a frontend later? Set VITE_CAPTCHA_PROVIDER=${captcha.provider} there too.`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
263
357
|
console.log('\nNext steps:');
|
|
264
358
|
console.log(` cd ${appName}/server`);
|
|
265
359
|
console.log(' npm install');
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-astram-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Scaffolder for a new Astram app — emits a running, framework-enforced NestJS server (deny-by-default, built-in auth/identity to switch on) and, with --with-frontend, a React admin/auth UI, over the immutable @astram/* framework packages.",
|
|
6
6
|
"type": "module",
|
|
@@ -4,3 +4,10 @@
|
|
|
4
4
|
# VITE_APP_LOGO_DARK=/my-logo-dark.png
|
|
5
5
|
# VITE_APP_TAGLINE=...
|
|
6
6
|
# VITE_APP_SUB_TAGLINE=...
|
|
7
|
+
#
|
|
8
|
+
# CAPTCHA provider this build allows in its Content-Security-Policy: turnstile | recaptcha-v3 |
|
|
9
|
+
# recaptcha-v2, or unset for none (index.html unchanged). It MUST equal the server's
|
|
10
|
+
# CAPTCHA_PROVIDER (server/.env); a mismatch shows a "misconfigured" notice on the login page.
|
|
11
|
+
# Read at build time (`npm run build`), so rebuild after changing it. No key goes here: the site
|
|
12
|
+
# key comes from the server at run time.
|
|
13
|
+
# VITE_CAPTCHA_PROVIDER=turnstile
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"test": "node scripts/run-tests.mjs"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@astram/frontend-core": "^0.
|
|
16
|
-
"@astram/sdk": "^0.2.
|
|
15
|
+
"@astram/frontend-core": "^0.8.0",
|
|
16
|
+
"@astram/sdk": "^0.2.1",
|
|
17
17
|
"@radix-ui/react-alert-dialog": "^1.1.19",
|
|
18
18
|
"@radix-ui/react-avatar": "^1.1.10",
|
|
19
19
|
"@radix-ui/react-checkbox": "^1.1.4",
|
|
@@ -27,6 +27,7 @@ import TwoFactorPage from './pages/account/TwoFactorPage';
|
|
|
27
27
|
import ReenrollPage from './pages/account/ReenrollPage';
|
|
28
28
|
import CompaniesPage from './pages/companies/CompaniesPage';
|
|
29
29
|
import CompanyForm from './pages/companies/CompanyForm';
|
|
30
|
+
import OrgStructurePage from './pages/org-structure/OrgStructurePage';
|
|
30
31
|
import RolesPage from './pages/roles/RolesPage';
|
|
31
32
|
import RoleForm from './pages/roles/RoleForm';
|
|
32
33
|
import UsersPage from './pages/users/UsersPage';
|
|
@@ -39,6 +40,7 @@ import ServiceAccountsPage from './pages/service-accounts/ServiceAccountsPage';
|
|
|
39
40
|
import GrantsPage from './pages/cross-tenant/GrantsPage';
|
|
40
41
|
import GrantForm from './pages/cross-tenant/GrantForm';
|
|
41
42
|
import InboxPage from './pages/cross-tenant/InboxPage';
|
|
43
|
+
import SecuritySettingsPage from './pages/security/SecuritySettingsPage';
|
|
42
44
|
|
|
43
45
|
/** Only-when-signed-out (auth screens bounce authenticated users to the app). */
|
|
44
46
|
function PublicOnly({ children }) {
|
|
@@ -192,6 +194,17 @@ export default function App() {
|
|
|
192
194
|
<Route path="add" element={<CompanyForm />} />
|
|
193
195
|
<Route path="edit/:uuid" element={<CompanyForm />} />
|
|
194
196
|
</Route>
|
|
197
|
+
{/* Org structure (G-012) — a company's departments and branches. Gated like the nav
|
|
198
|
+
entry (`identity:company_department:read`; `gate` takes one key); add, rename and
|
|
199
|
+
delete are department|branch:create|update|delete, enforced server-side. */}
|
|
200
|
+
<Route
|
|
201
|
+
path="/org-structure"
|
|
202
|
+
element={
|
|
203
|
+
<RequireAuth gate="identity:company_department:read">
|
|
204
|
+
<OrgStructurePage />
|
|
205
|
+
</RequireAuth>
|
|
206
|
+
}
|
|
207
|
+
/>
|
|
195
208
|
<Route
|
|
196
209
|
path="/roles"
|
|
197
210
|
element={
|
|
@@ -278,6 +291,17 @@ export default function App() {
|
|
|
278
291
|
</RequireAuth>
|
|
279
292
|
}
|
|
280
293
|
/>
|
|
294
|
+
{/* Security settings (auth capabilities R13.4) — mandatory-2FA policies. Gated
|
|
295
|
+
identity:security_policy:read (security-policy.controller.ts `GET security-policies`);
|
|
296
|
+
add/edit/delete are security_policy:create|update|delete, enforced server-side. */}
|
|
297
|
+
<Route
|
|
298
|
+
path="/security"
|
|
299
|
+
element={
|
|
300
|
+
<RequireAuth gate="identity:security_policy:read">
|
|
301
|
+
<SecuritySettingsPage />
|
|
302
|
+
</RequireAuth>
|
|
303
|
+
}
|
|
304
|
+
/>
|
|
281
305
|
<Route path="*" element={<Navigate to="/dashboard" replace />} />
|
|
282
306
|
</Routes>
|
|
283
307
|
);
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
createIdentityService,
|
|
20
20
|
createRecordPolicyService,
|
|
21
21
|
createRecordShareService,
|
|
22
|
+
createSecurityPolicyService,
|
|
22
23
|
createServiceAccountService,
|
|
23
24
|
createRefreshingHttp,
|
|
24
25
|
isAuthenticated,
|
|
@@ -28,7 +29,13 @@ import { createWebHttpClient } from '../platform/httpClient';
|
|
|
28
29
|
import { createWebSessionStore } from '../platform/sessionStore';
|
|
29
30
|
import { createWebShieldTransport } from '../platform/shieldTransport';
|
|
30
31
|
import { saveReturnPath } from '../platform/returnPathStore';
|
|
31
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
afterDeviceConfirmed,
|
|
34
|
+
clearSessionViews,
|
|
35
|
+
crossTabChange,
|
|
36
|
+
establishSession as runEstablishSession,
|
|
37
|
+
factsScopeOf,
|
|
38
|
+
} from './sessionFlow';
|
|
32
39
|
|
|
33
40
|
const AuthContext = createContext(null);
|
|
34
41
|
|
|
@@ -39,15 +46,20 @@ export function AuthProvider({ children }) {
|
|
|
39
46
|
// so the router re-renders. Until a fresh device is confirmed, the app forces the
|
|
40
47
|
// re-enroll screen (§4). Set on either (a) a `mfaRecoveryUsed:true` login result, or
|
|
41
48
|
// (b) the app-wide 403 `reenrollment_required` interceptor catching a blocked request.
|
|
49
|
+
// R2.3: a policy that requires 2FA restricts the session the same way (`mfa_enrollment`);
|
|
50
|
+
// `restrictionReason` lets the enrolment screen word its heading per reason.
|
|
42
51
|
const [mustReenroll, setMustReenroll] = useState(false);
|
|
52
|
+
const [restrictionReason, setRestrictionReason] = useState(null);
|
|
43
53
|
const reenrollRef = useRef(false);
|
|
44
|
-
const markReenroll = () => {
|
|
54
|
+
const markReenroll = (reason = 'reenroll') => {
|
|
45
55
|
if (reenrollRef.current) return; // already flagged — avoid redundant re-renders
|
|
46
56
|
reenrollRef.current = true;
|
|
57
|
+
setRestrictionReason(reason);
|
|
47
58
|
setMustReenroll(true);
|
|
48
59
|
};
|
|
49
60
|
const clearReenroll = () => {
|
|
50
61
|
reenrollRef.current = false;
|
|
62
|
+
setRestrictionReason(null);
|
|
51
63
|
setMustReenroll(false);
|
|
52
64
|
};
|
|
53
65
|
|
|
@@ -70,7 +82,8 @@ export function AuthProvider({ children }) {
|
|
|
70
82
|
// `{ error: 'reenrollment_required' }` (the enforced-re-enroll gate, §4) flips the
|
|
71
83
|
// app into the forced re-enroll flow. Matched narrowly so a future permission-deny
|
|
72
84
|
// 403 never triggers it.
|
|
73
|
-
|
|
85
|
+
// R2.3: `mfa_enrollment_required` (and the restricted auth-facts answer) route the same way.
|
|
86
|
+
const rawHttp = createWebHttpClient({ onRestricted: (reason) => markReenroll(reason) });
|
|
74
87
|
const store = createWebSessionStore();
|
|
75
88
|
// Token refresh (#12): every service talks through `http`, which turns a 401 on a
|
|
76
89
|
// request that carried a bearer token into ONE shared refresh (single-flight, and a
|
|
@@ -96,6 +109,8 @@ export function AuthProvider({ children }) {
|
|
|
96
109
|
// The guided rule-builder surface (§9.1) — author/list/delete record-access policies +
|
|
97
110
|
// the field/operator schema that drives the builder's dropdowns.
|
|
98
111
|
recordPolicy: createRecordPolicyService(http),
|
|
112
|
+
// 2FA security policies (R2): the Security settings page.
|
|
113
|
+
securityPolicy: createSecurityPolicyService(http),
|
|
99
114
|
// The owner-share surface (§9.2) — share/unshare/list a record's shares (owner-only).
|
|
100
115
|
recordShare: createRecordShareService(http),
|
|
101
116
|
// Service accounts (ADR-0033) — list/create/edit machine accounts + issue/rotate/revoke
|
|
@@ -104,6 +119,8 @@ export function AuthProvider({ children }) {
|
|
|
104
119
|
account: createAccountService(http),
|
|
105
120
|
// The @astram/sdk ShieldClient (Phase E slice 1) — a UX-convenience projection of
|
|
106
121
|
// the caller's OWN coarse grants, fetched once per session via `getAuthFacts`.
|
|
122
|
+
// Built once, so every session boundary calls `shield.reset()` (establishSession,
|
|
123
|
+
// resetSessionViews) and every fetch is scoped to its session (KI #139).
|
|
107
124
|
// NEVER the security boundary: the server's decide() on every @Classified route
|
|
108
125
|
// is the real enforcement (see shieldTransport.js's header doc). `getToken` reads
|
|
109
126
|
// `tokenRef.current` (not a closed-over value) so the SAME client instance always
|
|
@@ -126,6 +143,7 @@ export function AuthProvider({ children }) {
|
|
|
126
143
|
audit,
|
|
127
144
|
crossTenant,
|
|
128
145
|
recordPolicy,
|
|
146
|
+
securityPolicy,
|
|
129
147
|
recordShare,
|
|
130
148
|
serviceAccounts,
|
|
131
149
|
account,
|
|
@@ -159,12 +177,15 @@ export function AuthProvider({ children }) {
|
|
|
159
177
|
store.save(value);
|
|
160
178
|
};
|
|
161
179
|
|
|
162
|
-
// Everything derived from a session that must not outlive it
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
180
|
+
// Everything derived from a session that must not outlive it, including the ShieldClient's
|
|
181
|
+
// cached projection (KI #139). Sign-out, expiry and a cross-tab session change all run this.
|
|
182
|
+
const resetSessionViews = () =>
|
|
183
|
+
clearSessionViews({
|
|
184
|
+
resetShield: () => shield.reset(),
|
|
185
|
+
setProfile,
|
|
186
|
+
setAuthFacts,
|
|
187
|
+
clearReenroll,
|
|
188
|
+
});
|
|
168
189
|
|
|
169
190
|
// Wire the refreshing http client's lifecycle callbacks (the client is built once above;
|
|
170
191
|
// these run only after a network round-trip, so binding them in an effect is early enough).
|
|
@@ -216,14 +237,16 @@ export function AuthProvider({ children }) {
|
|
|
216
237
|
// RESOLVED projection, never reset to `null` mid-poll. `principalId` absent (no
|
|
217
238
|
// session yet) → skip, leaving `authFacts` at its fail-closed `null` (useCan
|
|
218
239
|
// hides/denies until known).
|
|
219
|
-
|
|
240
|
+
// `scope` (tenant + session, from factsScopeOf) keys the SDK's projection cache, so a
|
|
241
|
+
// projection cached for another session or tenant is never served here (KI #139).
|
|
242
|
+
const refreshAuthFacts = async (principalId, scope) => {
|
|
220
243
|
if (!principalId) {
|
|
221
244
|
setAuthFacts(null);
|
|
222
245
|
return;
|
|
223
246
|
}
|
|
224
247
|
let projection;
|
|
225
248
|
try {
|
|
226
|
-
projection = await shield.getAuthFacts(principalId);
|
|
249
|
+
projection = await shield.getAuthFacts(principalId, scope);
|
|
227
250
|
} catch {
|
|
228
251
|
projection = null; // getAuthFacts is documented never to throw; belt and braces
|
|
229
252
|
}
|
|
@@ -243,6 +266,7 @@ export function AuthProvider({ children }) {
|
|
|
243
266
|
runEstablishSession(
|
|
244
267
|
{ session, tokens, identityHint },
|
|
245
268
|
{
|
|
269
|
+
resetShield: () => shield.reset(),
|
|
246
270
|
persist,
|
|
247
271
|
setCurrentToken: (token) => {
|
|
248
272
|
tokenRef.current = token;
|
|
@@ -252,8 +276,20 @@ export function AuthProvider({ children }) {
|
|
|
252
276
|
},
|
|
253
277
|
);
|
|
254
278
|
|
|
255
|
-
|
|
256
|
-
|
|
279
|
+
// A device was confirmed (Two-factor page, or the re-enroll screen): refetch the auth facts
|
|
280
|
+
// (after a ShieldClient reset) and the profile, then lift any restriction (sessionFlow.js).
|
|
281
|
+
// Without this the nav stayed denied and the grace banner stayed until the 60 s poll.
|
|
282
|
+
const deviceConfirmed = () =>
|
|
283
|
+
afterDeviceConfirmed({
|
|
284
|
+
resetShield: () => shield.reset(),
|
|
285
|
+
refreshAuthFacts: () => refreshAuthFacts(principalOf(state), factsScopeOf(state?.session)),
|
|
286
|
+
loadProfile: () => loadProfile(state?.tokens?.accessToken),
|
|
287
|
+
clearRestriction: clearReenroll,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// `opts.captchaToken` (R7.3): sent when the login page has a solved CAPTCHA.
|
|
291
|
+
const login = async (identityHint, password, opts) => {
|
|
292
|
+
const r = await auth.login(identityHint, password, opts);
|
|
257
293
|
if (r.ok === true) {
|
|
258
294
|
await establishSession(r.session, r.tokens, identityHint);
|
|
259
295
|
}
|
|
@@ -284,12 +320,10 @@ export function AuthProvider({ children }) {
|
|
|
284
320
|
};
|
|
285
321
|
|
|
286
322
|
const logout = async () => {
|
|
287
|
-
const
|
|
323
|
+
const held = state; // { session, tokens }: the server needs a token as proof (R15.1)
|
|
288
324
|
persist(null); // clear locally first — the UI must never wait on the server
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
clearReenroll(); // a fresh sign-in starts unrestricted
|
|
292
|
-
await rawAuth.logout(sessionId); // raw client: no refresh/expiry path on a logout
|
|
325
|
+
resetSessionViews(); // profile, facts, restriction flags and the ShieldClient cache
|
|
326
|
+
await rawAuth.logout(held); // raw client: no refresh/expiry path on a logout
|
|
293
327
|
};
|
|
294
328
|
|
|
295
329
|
// On mount (e.g. a page refresh that rehydrated a persisted session), fetch the
|
|
@@ -298,7 +332,9 @@ export function AuthProvider({ children }) {
|
|
|
298
332
|
useEffect(() => {
|
|
299
333
|
const token = state?.tokens?.accessToken;
|
|
300
334
|
if (token && profile === null) void loadProfile(token);
|
|
301
|
-
if (token && authFacts === null)
|
|
335
|
+
if (token && authFacts === null) {
|
|
336
|
+
void refreshAuthFacts(principalOf(state), factsScopeOf(state?.session));
|
|
337
|
+
}
|
|
302
338
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
303
339
|
}, []);
|
|
304
340
|
|
|
@@ -310,14 +346,12 @@ export function AuthProvider({ children }) {
|
|
|
310
346
|
store.subscribe((next) => {
|
|
311
347
|
const prevSessionId = sessionIdRef.current;
|
|
312
348
|
setState(next);
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if (next.session?.sessionId !== prevSessionId) {
|
|
318
|
-
resetSessionViews();
|
|
349
|
+
const change = crossTabChange(prevSessionId, next);
|
|
350
|
+
if (change === 'rotated') return; // same session, new tokens: keep the views
|
|
351
|
+
resetSessionViews(); // signed out or a different sign-in: drop this session's views
|
|
352
|
+
if (change === 'switched') {
|
|
319
353
|
void loadProfile(next.tokens?.accessToken);
|
|
320
|
-
void refreshAuthFacts(principalOf(next));
|
|
354
|
+
void refreshAuthFacts(principalOf(next), factsScopeOf(next.session));
|
|
321
355
|
}
|
|
322
356
|
}),
|
|
323
357
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -346,8 +380,9 @@ export function AuthProvider({ children }) {
|
|
|
346
380
|
if (!token) return undefined; // not authenticated — nothing to keep fresh
|
|
347
381
|
|
|
348
382
|
const principalId = principalOf(state);
|
|
383
|
+
const scope = factsScopeOf(state?.session);
|
|
349
384
|
const poke = () => {
|
|
350
|
-
if (principalId) void refreshAuthFacts(principalId);
|
|
385
|
+
if (principalId) void refreshAuthFacts(principalId, scope);
|
|
351
386
|
};
|
|
352
387
|
|
|
353
388
|
const onFocus = () => poke();
|
|
@@ -363,7 +398,7 @@ export function AuthProvider({ children }) {
|
|
|
363
398
|
// Re-armed whenever the token/principal changes (login/logout/refresh) so a stale
|
|
364
399
|
// closure never keeps polling for a signed-out or since-replaced session.
|
|
365
400
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
366
|
-
}, [state?.tokens?.accessToken, state?.session?.principalId]);
|
|
401
|
+
}, [state?.tokens?.accessToken, state?.session?.principalId, state?.session?.sessionId]);
|
|
367
402
|
|
|
368
403
|
const value = useMemo(
|
|
369
404
|
() => ({
|
|
@@ -380,9 +415,13 @@ export function AuthProvider({ children }) {
|
|
|
380
415
|
// True while the current session is restricted to re-securing the account
|
|
381
416
|
// (recovery-code login). The router forces the re-enroll screen until cleared.
|
|
382
417
|
mustReenroll,
|
|
383
|
-
//
|
|
384
|
-
|
|
418
|
+
// Why the session is restricted: 'reenroll' | 'mfa_enrollment' | null (R2.3).
|
|
419
|
+
restrictionReason,
|
|
420
|
+
// Clear the restriction locally (no refetch). A device confirm uses deviceConfirmed.
|
|
385
421
|
clearReenroll,
|
|
422
|
+
// After a device confirm: refetch facts + profile, then lift the restriction (the server
|
|
423
|
+
// has already lifted it on this token). Awaited by TwoFactorPage before its callback.
|
|
424
|
+
deviceConfirmed,
|
|
386
425
|
login,
|
|
387
426
|
// Complete a pending MFA challenge (second factor) — same session-establish
|
|
388
427
|
// path as login. Consumed by the Login page's MFA code step.
|
|
@@ -402,6 +441,8 @@ export function AuthProvider({ children }) {
|
|
|
402
441
|
// The shared guided rule-builder service (author/list/delete record policies + the
|
|
403
442
|
// field/operator schema) — same injected web http client.
|
|
404
443
|
recordPolicy,
|
|
444
|
+
// The 2FA security-policy service (Security settings page) — same client.
|
|
445
|
+
securityPolicy,
|
|
405
446
|
// The shared owner-share service (share/unshare/list a record's shares) — same client.
|
|
406
447
|
recordShare,
|
|
407
448
|
// The shared service-accounts service (list/create/edit + issue/rotate/revoke keys).
|
|
@@ -438,12 +479,14 @@ export function AuthProvider({ children }) {
|
|
|
438
479
|
audit,
|
|
439
480
|
crossTenant,
|
|
440
481
|
recordPolicy,
|
|
482
|
+
securityPolicy,
|
|
441
483
|
recordShare,
|
|
442
484
|
serviceAccounts,
|
|
443
485
|
account,
|
|
444
486
|
shield,
|
|
445
487
|
profile,
|
|
446
488
|
mustReenroll,
|
|
489
|
+
restrictionReason,
|
|
447
490
|
authFacts,
|
|
448
491
|
],
|
|
449
492
|
);
|