@ofidj/generator-fidj 3.10.0 → 3.10.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.
|
@@ -308,6 +308,60 @@ function offerTheWindowBack(providerWindow: ProviderWindow) {
|
|
|
308
308
|
waiting.insertAdjacentElement("afterend", cancel);
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
+
// Being recognised by Fidj is not the same as having signed in here. An app's
|
|
312
|
+
// door writes the session the provider holds, and Fidj's own entry used to read
|
|
313
|
+
// none of it — so somebody who had just joined an app was asked for a password
|
|
314
|
+
// by the account provider itself, one screen later.
|
|
315
|
+
//
|
|
316
|
+
// `prompt=none` asks the provider to answer without showing anything: a code
|
|
317
|
+
// when it knows this browser, `login_required` when it does not. Those are
|
|
318
|
+
// exactly the two cases to tell apart, and neither costs a screen.
|
|
319
|
+
//
|
|
320
|
+
// Only where Fidj is the app. An app with a door of its own must keep it: taking
|
|
321
|
+
// that door is where the app's own agreement is asked and recorded, and signing
|
|
322
|
+
// somebody in around it would skip a decision they never made.
|
|
323
|
+
const RECOGNITION_ASKED = "fidj.oidc.recognition-asked";
|
|
324
|
+
// A page that is public is exactly where a session is not what somebody came
|
|
325
|
+
// for. Asking there sent an anonymous visitor to the provider and back, and what
|
|
326
|
+
// they had asked to read never rendered.
|
|
327
|
+
const PUBLIC_ROUTE = "pub";
|
|
328
|
+
// Whether the question is still outstanding. Drawing the credential form and
|
|
329
|
+
// then navigating to the provider loses whatever somebody had begun typing, so
|
|
330
|
+
// the entry waits instead — the answer takes one redirect, not a wait worth a
|
|
331
|
+
// spinner's worth of ceremony, and it says what it is doing.
|
|
332
|
+
let recognising = false;
|
|
333
|
+
function mightBeRecognised() {
|
|
334
|
+
if (!oidc || !isFidjItself) return false;
|
|
335
|
+
if ((moduleRoute() || "").split("/")[0] === PUBLIC_ROUTE) return false;
|
|
336
|
+
if (oidc.signedOutHere()) return false;
|
|
337
|
+
try {
|
|
338
|
+
return sessionStorage.getItem(RECOGNITION_ASKED) !== "true";
|
|
339
|
+
} catch {
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async function askWhetherFidjKnowsThisBrowser() {
|
|
345
|
+
if (!oidc || !isFidjItself || sdk.isLoggedIn() || oidc.signedOutHere())
|
|
346
|
+
return false;
|
|
347
|
+
if ((moduleRoute() || "").split("/")[0] === PUBLIC_ROUTE) return false;
|
|
348
|
+
// Once per document: the answer comes back as a redirect to this same page,
|
|
349
|
+
// so without this a refusal would ask again, and again.
|
|
350
|
+
try {
|
|
351
|
+
if (sessionStorage.getItem(RECOGNITION_ASKED) === "true") return false;
|
|
352
|
+
sessionStorage.setItem(RECOGNITION_ASKED, "true");
|
|
353
|
+
} catch {
|
|
354
|
+
return false;
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
window.location.assign(await oidc.beginLogin({ silent: true }));
|
|
358
|
+
return true;
|
|
359
|
+
} catch {
|
|
360
|
+
// No provider, or it would not say. The entry is still there to be used.
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
311
365
|
function signInThroughProvider(
|
|
312
366
|
trigger: HTMLElement | null,
|
|
313
367
|
options: { silent?: boolean; prompt?: string } = {},
|
|
@@ -544,6 +598,10 @@ function render() {
|
|
|
544
598
|
renderNav("content");
|
|
545
599
|
return;
|
|
546
600
|
}
|
|
601
|
+
if (recognising) {
|
|
602
|
+
root.innerHTML = `<section class="signin-shell"><div class="signin-form"><p role="status">Checking whether you are already signed in to Fidj…</p></div></section>`;
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
547
605
|
// Only the entry reaches here now: the privacy screen and the account
|
|
548
606
|
// screen became one, and that one is drawn above.
|
|
549
607
|
root.innerHTML = `<section class="signin-shell"><div class="signin-intro${config.highlights?.length ? "" : " is-plain"}"><header class="signin-masthead"><img class="app-mark" src="${escape(config.logo)}" alt=""><strong>${escape(config.title)}</strong></header>
|
|
@@ -1081,6 +1139,7 @@ if (relayProviderAnswer()) {
|
|
|
1081
1139
|
|
|
1082
1140
|
function boot() {
|
|
1083
1141
|
window.addEventListener("hashchange", render);
|
|
1142
|
+
recognising = mightBeRecognised();
|
|
1084
1143
|
render();
|
|
1085
1144
|
if (readInteraction()) {
|
|
1086
1145
|
render();
|
|
@@ -1100,7 +1159,27 @@ function boot() {
|
|
|
1100
1159
|
if (oidc && new URL(window.location.href).searchParams.has("state")) {
|
|
1101
1160
|
const callback = new URL(window.location.href);
|
|
1102
1161
|
window.history.replaceState(null, "", window.location.pathname + "#/content");
|
|
1103
|
-
|
|
1162
|
+
try {
|
|
1163
|
+
await oidc.completeLogin(callback);
|
|
1164
|
+
} catch (refusal) {
|
|
1165
|
+
const why = (refusal as {code?: string; silentRefusal?: boolean}) || {};
|
|
1166
|
+
// A silent question answered "no" is an answer, not a failure. But the
|
|
1167
|
+
// two ways of saying no mean opposite things here.
|
|
1168
|
+
//
|
|
1169
|
+
// `login_required` — the provider does not know this browser, and the
|
|
1170
|
+
// entry is the right next screen.
|
|
1171
|
+
//
|
|
1172
|
+
// `consent_required` — it knows exactly who this is; what it has not got
|
|
1173
|
+
// is this client's permission, because the account was made through
|
|
1174
|
+
// another app and Fidj's console is a client of its own. Asking again
|
|
1175
|
+
// without `prompt=none` gets the screen that collects it, and no
|
|
1176
|
+
// password: the person already typed theirs once.
|
|
1177
|
+
if (why.code === "consent_required") {
|
|
1178
|
+
window.location.assign(await oidc.beginLogin());
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
if (!why.silentRefusal) throw refusal;
|
|
1182
|
+
}
|
|
1104
1183
|
try {
|
|
1105
1184
|
sessionStorage.removeItem("fidj.interaction.email");
|
|
1106
1185
|
} catch {}
|
|
@@ -1109,10 +1188,16 @@ function boot() {
|
|
|
1109
1188
|
apiEndpoint: config.apiEndpoint,
|
|
1110
1189
|
prod: !config.localDemo,
|
|
1111
1190
|
});
|
|
1191
|
+
recognising = recognising && !sdk.isLoggedIn();
|
|
1112
1192
|
if (sdk.isLoggedIn()) {
|
|
1113
1193
|
await refresh();
|
|
1114
1194
|
if (!moduleRoute() && !accountRoutes.includes(currentRoute()))
|
|
1115
1195
|
navigate("content");
|
|
1196
|
+
return;
|
|
1116
1197
|
}
|
|
1198
|
+
// Nothing held here. Fidj may still know this browser from an app.
|
|
1199
|
+
if (await askWhetherFidjKnowsThisBrowser()) return;
|
|
1200
|
+
recognising = false;
|
|
1201
|
+
render();
|
|
1117
1202
|
});
|
|
1118
1203
|
}
|