@atlasauth/js 0.10.0 → 0.12.0
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/CHANGELOG.md +40 -0
- package/dist/atlas-captcha.d.ts +108 -0
- package/dist/atlas-captcha.js +315 -0
- package/dist/atlas-captcha.js.map +1 -0
- package/dist/captcha-controller.d.ts +11 -1
- package/dist/captcha-controller.js +5 -3
- package/dist/captcha-controller.js.map +1 -1
- package/dist/captcha-widget.d.ts +21 -2
- package/dist/captcha-widget.js +23 -11
- package/dist/captcha-widget.js.map +1 -1
- package/dist/captcha.js +14 -0
- package/dist/captcha.js.map +1 -1
- package/dist/fapi.d.ts +29 -0
- package/dist/fapi.js +30 -0
- package/dist/fapi.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/initial-state.d.ts +34 -0
- package/dist/initial-state.js +53 -0
- package/dist/initial-state.js.map +1 -0
- package/dist/instance-settings.js +4 -0
- package/dist/instance-settings.js.map +1 -1
- package/dist/sdk-advisory.d.ts +44 -0
- package/dist/sdk-advisory.js +69 -0
- package/dist/sdk-advisory.js.map +1 -0
- package/dist/sign-out-events.d.ts +54 -0
- package/dist/sign-out-events.js +97 -0
- package/dist/sign-out-events.js.map +1 -0
- package/dist/version.d.ts +7 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# @atlasauth/js changelog
|
|
2
2
|
|
|
3
|
+
## 0.12.0
|
|
4
|
+
- **New: SDK identity and advisories.** `FapiClientOptions.sdk?: AtlasSdkInfo` (`{ name, version }`, default
|
|
5
|
+
`@atlasauth/js`) is sent as `X-Atlas-SDK: <name>/<version>`; an `Atlas-SDK-Advisory` response header is logged once
|
|
6
|
+
per advisory per page load. New exports: `ATLAS_JS_VERSION`, `ATLAS_JS_SDK`, `AtlasSdkInfo`, `SDK_HEADER`,
|
|
7
|
+
`SDK_ADVISORY_HEADER`, `sdkHeaderValue()`, `parseSdkAdvisory()`, `reportSdkAdvisory()`, `resetSdkAdvisoryLog()`,
|
|
8
|
+
`SdkAdvisoryNotice`.
|
|
9
|
+
- **New: sign-out events.** `SignOutNotifier` (`subscribe`, `expect(reason)`, `clear`, `signedOut(sessionId, fallback?)`),
|
|
10
|
+
`SignOutEvent` (`{ reason, sessionId }`), `SignOutReason` (`'user' | 'other_tab' | 'session_expired' | 'revoked' |
|
|
11
|
+
'unknown'`), `SignOutListener`, `SIGN_OUT_EVENT` (`'atlas:signout'`), `dispatchSignOutEvent()`, `onAtlasSignOut()` and
|
|
12
|
+
`signOutReasonFromClient()` (reads the new `signed_out_reason` of a signed-out `GET /v1/client`). Every framework
|
|
13
|
+
provider drives one.
|
|
14
|
+
- **New: `getTemplateToken(client, sessionId, template)`** → `{ jwt, expiresIn } | null` (`getToken({ template })`), and
|
|
15
|
+
**`getForumulateReaderToken(client, spaceId?)`** → `{ jwt, expiresIn, orgId, spaceId, redeemUrl } | null`
|
|
16
|
+
(`GET /v1/client/forumulate/reader_token`).
|
|
17
|
+
- **New: the Atlas captcha (provider `atlas`).** Atlas's own captcha needs no provider account or keys.
|
|
18
|
+
`renderCaptchaWidget` (and so every prebuilt form using `createCaptchaController`) draws it when a flow's provider is
|
|
19
|
+
`atlas`: it fetches a challenge, solves the proof of work in Web Workers (on the page when workers are blocked) and
|
|
20
|
+
shows the shape-matching step only when the server asks for it, with an accessible alternative.
|
|
21
|
+
- **New exports:** `renderAtlasCaptcha(container, { fetchChallenge?, challengeUrl?, mode?, labels?, workers? })` →
|
|
22
|
+
`{ token: Promise<string>; stale(): boolean; remove(): void }`, `solveAtlasChallenge(challenge, { workers?, cancelled? })`
|
|
23
|
+
→ `Promise<{ n, worker }>`, `searchAtlasRange`, `fetchAtlasChallenge(url, accessible?)`, `encodeAtlasToken(solution)`,
|
|
24
|
+
`ATLAS_CAPTCHA_LABELS`, types `AtlasChallenge`, `AtlasCaptchaOptions`, `AtlasCaptchaLabels`, `AtlasCaptchaHandle`.
|
|
25
|
+
- **Added `FlowCaptcha.challengeUrl?: string`** (read from `/v1/appearance` `captchaFlows[flow].challengeUrl`).
|
|
26
|
+
- **Added `CaptchaWidgetHandle.stale?(): boolean`**: a solved token about to expire unspent; the captcha controller
|
|
27
|
+
draws a fresh widget instead of sending it.
|
|
28
|
+
- **Added an optional third argument to `renderCaptchaWidget` / `getCaptchaToken`:** `{ atlas?: { fetchChallenge?, labels?, workers? } }`.
|
|
29
|
+
- `captcha(client).protect(el, action?)` supports `atlas` (the challenge is fetched through the client).
|
|
30
|
+
- **New: `atlasCaptchaLabels(lookup)`** → `Partial<AtlasCaptchaLabels>` from a translator or a flat catalog (keys in
|
|
31
|
+
`ATLAS_CAPTCHA_LABEL_KEYS`, e.g. `captcha.puzzleTile`); unknown or echoed keys keep the English default.
|
|
32
|
+
- **New: second argument to `createCaptchaController(initial?, settings?)`**: `{ atlasLabels?: () => Partial<AtlasCaptchaLabels> }`,
|
|
33
|
+
read each time a widget is drawn. New type `CaptchaControllerSettings`.
|
|
34
|
+
|
|
35
|
+
## 0.11.0
|
|
36
|
+
- **New: `fetchAtlasInitialState({ publishableKey, frontendApi, fetchImpl?, init?, timeoutMs? })`** →
|
|
37
|
+
`Promise<AtlasInitialState>` (`{ appearance?: unknown; environment?: unknown }`). Fetches `/v1/appearance` and
|
|
38
|
+
`/v1/client/environment` in parallel on the server, for a provider's `initialState`. Never throws: a part that
|
|
39
|
+
fails or takes longer than `timeoutMs` (default 1500) is left out. `init` is passed to both requests (for example
|
|
40
|
+
`{ next: { revalidate: 60 } }`).
|
|
41
|
+
- New types `AtlasInitialState` and `FetchInitialStateOptions`.
|
|
42
|
+
|
|
3
43
|
## 0.10.0
|
|
4
44
|
- **New: `planFirstFactor(offered)`** → `{ password: boolean; email: ('email_code' | 'email_link')[]; autoSend: 'email_code' | 'email_link' | null }`.
|
|
5
45
|
The rule every prebuilt sign-in form follows: a password field only when the server offers `password`; with no
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Atlas's own captcha (provider `atlas`), the browser half. Dependency-free.
|
|
3
|
+
*
|
|
4
|
+
* No third-party script and no site key: the widget fetches a signed,
|
|
5
|
+
* single-use challenge from the instance's Frontend API, finds the number `n`
|
|
6
|
+
* with SHA-256(salt + n) = challenge (proof of work, in Web Workers via
|
|
7
|
+
* `crypto.subtle`, falling back to the page thread when workers are blocked),
|
|
8
|
+
* and, only when the server decided the request looks risky, shows a
|
|
9
|
+
* "select every matching shape" step with an accessible alternative (more
|
|
10
|
+
* work instead of the puzzle). The flow's request then carries
|
|
11
|
+
* `atlas1.<base64url JSON>` as `captcha_token`.
|
|
12
|
+
*
|
|
13
|
+
* Invisible by default: at low risk nothing is drawn and the work takes a
|
|
14
|
+
* fraction of a second.
|
|
15
|
+
*/
|
|
16
|
+
/** A challenge, exactly as `GET /v1/client/captcha/challenge` returns it. */
|
|
17
|
+
export interface AtlasChallenge {
|
|
18
|
+
object: 'captcha_challenge';
|
|
19
|
+
provider: 'atlas';
|
|
20
|
+
token: string;
|
|
21
|
+
algorithm: 'SHA-256';
|
|
22
|
+
salt: string;
|
|
23
|
+
challenge: string;
|
|
24
|
+
maxnumber: number;
|
|
25
|
+
expires_at: string;
|
|
26
|
+
interactive: {
|
|
27
|
+
kind: 'match_shapes';
|
|
28
|
+
example: string;
|
|
29
|
+
tiles: string[];
|
|
30
|
+
} | null;
|
|
31
|
+
accessible_alternative: boolean;
|
|
32
|
+
}
|
|
33
|
+
/** The words the widget shows. English defaults; pass your own to localise. */
|
|
34
|
+
export interface AtlasCaptchaLabels {
|
|
35
|
+
checking: string;
|
|
36
|
+
verified: string;
|
|
37
|
+
puzzlePrompt: string;
|
|
38
|
+
confirm: string;
|
|
39
|
+
/** `{n}` is the tile number. */
|
|
40
|
+
tile: string;
|
|
41
|
+
alternative: string;
|
|
42
|
+
}
|
|
43
|
+
export declare const ATLAS_CAPTCHA_LABELS: AtlasCaptchaLabels;
|
|
44
|
+
/**
|
|
45
|
+
* The catalog keys of the widget's words, as in `@atlasauth/localizations` and
|
|
46
|
+
* every SDK's built-in catalog.
|
|
47
|
+
*/
|
|
48
|
+
export declare const ATLAS_CAPTCHA_LABEL_KEYS: Readonly<Record<keyof AtlasCaptchaLabels, string>>;
|
|
49
|
+
/**
|
|
50
|
+
* The widget's labels from a form's translator (or any catalog lookup). A key
|
|
51
|
+
* the lookup does not know (no value, or the key echoed back) keeps the English
|
|
52
|
+
* default.
|
|
53
|
+
*/
|
|
54
|
+
export declare function atlasCaptchaLabels(lookup: ((key: string) => string | null | undefined) | Readonly<Record<string, unknown>> | null | undefined): Partial<AtlasCaptchaLabels>;
|
|
55
|
+
export interface AtlasCaptchaOptions {
|
|
56
|
+
/**
|
|
57
|
+
* Fetch a fresh challenge. Defaults to a GET of the flow's `challengeUrl`
|
|
58
|
+
* (from `/v1/appearance`). `accessible` asks for the no-puzzle alternative.
|
|
59
|
+
*/
|
|
60
|
+
fetchChallenge?: (accessible: boolean) => Promise<AtlasChallenge>;
|
|
61
|
+
/** Where the default fetcher GETs (the flow's `challengeUrl`). */
|
|
62
|
+
challengeUrl?: string;
|
|
63
|
+
/**
|
|
64
|
+
* `managed` (default) solves as soon as it is drawn and shows nothing unless
|
|
65
|
+
* the puzzle is needed; `invisible` is the same, drawn only at submit;
|
|
66
|
+
* `visible` always shows the check (and the server always adds the puzzle).
|
|
67
|
+
*/
|
|
68
|
+
mode?: 'invisible' | 'managed' | 'visible';
|
|
69
|
+
labels?: Partial<AtlasCaptchaLabels>;
|
|
70
|
+
/** Use Web Workers when available (default true). */
|
|
71
|
+
workers?: boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Search [from, to] for n with SHA-256(salt + n) = challenge, on this thread.
|
|
75
|
+
* Each batch awaits `crypto.subtle`, so the page stays responsive.
|
|
76
|
+
*/
|
|
77
|
+
export declare function searchAtlasRange(c: Pick<AtlasChallenge, 'salt' | 'challenge'>, from: number, to: number, cancelled?: () => boolean): Promise<number | null>;
|
|
78
|
+
/**
|
|
79
|
+
* Solve a challenge's proof of work. Splits the range over up to four Web
|
|
80
|
+
* Workers; when workers cannot start (a CSP without `worker-src blob:`, an old
|
|
81
|
+
* browser) it searches on this thread instead. Resolves `{ n, worker }`.
|
|
82
|
+
*/
|
|
83
|
+
export declare function solveAtlasChallenge(c: Pick<AtlasChallenge, 'salt' | 'challenge' | 'maxnumber'>, opts?: {
|
|
84
|
+
workers?: boolean;
|
|
85
|
+
cancelled?: () => boolean;
|
|
86
|
+
}): Promise<{
|
|
87
|
+
n: number;
|
|
88
|
+
worker: boolean;
|
|
89
|
+
}>;
|
|
90
|
+
/** Encode a solution as the `captcha_token` the flow's request carries. */
|
|
91
|
+
export declare function encodeAtlasToken(s: {
|
|
92
|
+
t: string;
|
|
93
|
+
n: number;
|
|
94
|
+
ms?: number;
|
|
95
|
+
w?: 0 | 1;
|
|
96
|
+
sel?: number;
|
|
97
|
+
}): string;
|
|
98
|
+
/** GET a challenge from a URL (the flow's `challengeUrl`). */
|
|
99
|
+
export declare function fetchAtlasChallenge(url: string, accessible?: boolean): Promise<AtlasChallenge>;
|
|
100
|
+
/** A drawn Atlas captcha: its token, whether it is about to expire, and teardown. */
|
|
101
|
+
export interface AtlasCaptchaHandle {
|
|
102
|
+
token: Promise<string>;
|
|
103
|
+
/** True once the solved challenge is within 15 s of expiring: draw a fresh one. */
|
|
104
|
+
stale(): boolean;
|
|
105
|
+
remove(): void;
|
|
106
|
+
}
|
|
107
|
+
/** Render Atlas's captcha into `container` and resolve the `captcha_token`. */
|
|
108
|
+
export declare function renderAtlasCaptcha(container: HTMLElement, opts: AtlasCaptchaOptions): AtlasCaptchaHandle;
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Atlas's own captcha (provider `atlas`), the browser half. Dependency-free.
|
|
4
|
+
*
|
|
5
|
+
* No third-party script and no site key: the widget fetches a signed,
|
|
6
|
+
* single-use challenge from the instance's Frontend API, finds the number `n`
|
|
7
|
+
* with SHA-256(salt + n) = challenge (proof of work, in Web Workers via
|
|
8
|
+
* `crypto.subtle`, falling back to the page thread when workers are blocked),
|
|
9
|
+
* and, only when the server decided the request looks risky, shows a
|
|
10
|
+
* "select every matching shape" step with an accessible alternative (more
|
|
11
|
+
* work instead of the puzzle). The flow's request then carries
|
|
12
|
+
* `atlas1.<base64url JSON>` as `captcha_token`.
|
|
13
|
+
*
|
|
14
|
+
* Invisible by default: at low risk nothing is drawn and the work takes a
|
|
15
|
+
* fraction of a second.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.ATLAS_CAPTCHA_LABEL_KEYS = exports.ATLAS_CAPTCHA_LABELS = void 0;
|
|
19
|
+
exports.atlasCaptchaLabels = atlasCaptchaLabels;
|
|
20
|
+
exports.searchAtlasRange = searchAtlasRange;
|
|
21
|
+
exports.solveAtlasChallenge = solveAtlasChallenge;
|
|
22
|
+
exports.encodeAtlasToken = encodeAtlasToken;
|
|
23
|
+
exports.fetchAtlasChallenge = fetchAtlasChallenge;
|
|
24
|
+
exports.renderAtlasCaptcha = renderAtlasCaptcha;
|
|
25
|
+
exports.ATLAS_CAPTCHA_LABELS = {
|
|
26
|
+
checking: 'Checking your browser…',
|
|
27
|
+
verified: 'Security check complete.',
|
|
28
|
+
puzzlePrompt: "Select every picture that shows the same shape as this one. Colour and size don't matter.",
|
|
29
|
+
confirm: 'Confirm',
|
|
30
|
+
tile: 'Picture {n}',
|
|
31
|
+
alternative: "Can't do the picture check? Use a longer automatic check instead.",
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The catalog keys of the widget's words, as in `@atlasauth/localizations` and
|
|
35
|
+
* every SDK's built-in catalog.
|
|
36
|
+
*/
|
|
37
|
+
exports.ATLAS_CAPTCHA_LABEL_KEYS = {
|
|
38
|
+
checking: 'captcha.checking',
|
|
39
|
+
verified: 'captcha.verified',
|
|
40
|
+
puzzlePrompt: 'captcha.puzzlePrompt',
|
|
41
|
+
confirm: 'captcha.puzzleConfirm',
|
|
42
|
+
tile: 'captcha.puzzleTile',
|
|
43
|
+
alternative: 'captcha.puzzleAlternative',
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The widget's labels from a form's translator (or any catalog lookup). A key
|
|
47
|
+
* the lookup does not know (no value, or the key echoed back) keeps the English
|
|
48
|
+
* default.
|
|
49
|
+
*/
|
|
50
|
+
function atlasCaptchaLabels(lookup) {
|
|
51
|
+
if (!lookup)
|
|
52
|
+
return {};
|
|
53
|
+
const get = typeof lookup === 'function' ? lookup : (key) => lookup[key];
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const [field, key] of Object.entries(exports.ATLAS_CAPTCHA_LABEL_KEYS)) {
|
|
56
|
+
const value = get(key);
|
|
57
|
+
if (typeof value === 'string' && value.trim() && value !== key)
|
|
58
|
+
out[field] = value;
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
const hex = (buf) => {
|
|
63
|
+
const b = new Uint8Array(buf);
|
|
64
|
+
let s = '';
|
|
65
|
+
for (let i = 0; i < b.length; i++)
|
|
66
|
+
s += (b[i] < 16 ? '0' : '') + b[i].toString(16);
|
|
67
|
+
return s;
|
|
68
|
+
};
|
|
69
|
+
const BATCH = 2000;
|
|
70
|
+
/**
|
|
71
|
+
* Search [from, to] for n with SHA-256(salt + n) = challenge, on this thread.
|
|
72
|
+
* Each batch awaits `crypto.subtle`, so the page stays responsive.
|
|
73
|
+
*/
|
|
74
|
+
async function searchAtlasRange(c, from, to, cancelled = () => false) {
|
|
75
|
+
const enc = new TextEncoder();
|
|
76
|
+
for (let start = from; start <= to; start += BATCH) {
|
|
77
|
+
if (cancelled())
|
|
78
|
+
return null;
|
|
79
|
+
const end = Math.min(to, start + BATCH - 1);
|
|
80
|
+
const batch = [];
|
|
81
|
+
for (let n = start; n <= end; n++)
|
|
82
|
+
batch.push(crypto.subtle.digest('SHA-256', enc.encode(`${c.salt}${n}`)));
|
|
83
|
+
const hashes = await Promise.all(batch);
|
|
84
|
+
for (let i = 0; i < hashes.length; i++)
|
|
85
|
+
if (hex(hashes[i]) === c.challenge)
|
|
86
|
+
return start + i;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
/** The worker: the same search, posted back as { n }. Kept as a string so it ships with no bundler setup. */
|
|
91
|
+
const WORKER_SOURCE = `
|
|
92
|
+
self.onmessage = async function (e) {
|
|
93
|
+
var d = e.data, enc = new TextEncoder();
|
|
94
|
+
function hex(buf) { var b = new Uint8Array(buf), s = ''; for (var i = 0; i < b.length; i++) s += (b[i] < 16 ? '0' : '') + b[i].toString(16); return s; }
|
|
95
|
+
for (var start = d.from; start <= d.to; start += ${BATCH}) {
|
|
96
|
+
var end = Math.min(d.to, start + ${BATCH} - 1), batch = [];
|
|
97
|
+
for (var n = start; n <= end; n++) batch.push(crypto.subtle.digest('SHA-256', enc.encode(d.salt + n)));
|
|
98
|
+
var hs = await Promise.all(batch);
|
|
99
|
+
for (var i = 0; i < hs.length; i++) if (hex(hs[i]) === d.challenge) { self.postMessage({ n: start + i }); return; }
|
|
100
|
+
}
|
|
101
|
+
self.postMessage({ n: null });
|
|
102
|
+
};`;
|
|
103
|
+
/**
|
|
104
|
+
* Solve a challenge's proof of work. Splits the range over up to four Web
|
|
105
|
+
* Workers; when workers cannot start (a CSP without `worker-src blob:`, an old
|
|
106
|
+
* browser) it searches on this thread instead. Resolves `{ n, worker }`.
|
|
107
|
+
*/
|
|
108
|
+
async function solveAtlasChallenge(c, opts = {}) {
|
|
109
|
+
const cancelled = opts.cancelled ?? (() => false);
|
|
110
|
+
const g = globalThis;
|
|
111
|
+
if (opts.workers !== false && g.Worker && g.Blob && g.URL?.createObjectURL) {
|
|
112
|
+
const viaWorkers = await solveInWorkers(c, Math.max(1, Math.min(4, g.navigator?.hardwareConcurrency ?? 2)), cancelled).catch(() => undefined);
|
|
113
|
+
if (viaWorkers !== undefined) {
|
|
114
|
+
if (viaWorkers === null)
|
|
115
|
+
throw new Error('captcha: no solution');
|
|
116
|
+
return { n: viaWorkers, worker: true };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const n = await searchAtlasRange(c, 0, c.maxnumber, cancelled);
|
|
120
|
+
if (n === null)
|
|
121
|
+
throw new Error(cancelled() ? 'captcha: cancelled' : 'captcha: no solution');
|
|
122
|
+
return { n, worker: false };
|
|
123
|
+
}
|
|
124
|
+
function solveInWorkers(c, count, cancelled) {
|
|
125
|
+
const url = URL.createObjectURL(new Blob([WORKER_SOURCE], { type: 'text/javascript' }));
|
|
126
|
+
const workers = [];
|
|
127
|
+
const stop = () => {
|
|
128
|
+
for (const w of workers)
|
|
129
|
+
w.terminate();
|
|
130
|
+
URL.revokeObjectURL(url);
|
|
131
|
+
};
|
|
132
|
+
return new Promise((resolve, reject) => {
|
|
133
|
+
let pending = count;
|
|
134
|
+
const span = Math.ceil((c.maxnumber + 1) / count);
|
|
135
|
+
const poll = setInterval(() => {
|
|
136
|
+
if (cancelled()) {
|
|
137
|
+
clearInterval(poll);
|
|
138
|
+
stop();
|
|
139
|
+
resolve(null);
|
|
140
|
+
}
|
|
141
|
+
}, 100);
|
|
142
|
+
const finish = (value) => {
|
|
143
|
+
clearInterval(poll);
|
|
144
|
+
stop();
|
|
145
|
+
if (value instanceof Error)
|
|
146
|
+
reject(value);
|
|
147
|
+
else
|
|
148
|
+
resolve(value);
|
|
149
|
+
};
|
|
150
|
+
try {
|
|
151
|
+
for (let i = 0; i < count; i++) {
|
|
152
|
+
const w = new Worker(url);
|
|
153
|
+
workers.push(w);
|
|
154
|
+
w.onmessage = (e) => {
|
|
155
|
+
if (typeof e.data?.n === 'number')
|
|
156
|
+
finish(e.data.n);
|
|
157
|
+
else if (--pending === 0)
|
|
158
|
+
finish(null);
|
|
159
|
+
};
|
|
160
|
+
w.onerror = () => finish(new Error('captcha: worker failed'));
|
|
161
|
+
const from = i * span;
|
|
162
|
+
w.postMessage({ salt: c.salt, challenge: c.challenge, from, to: Math.min(c.maxnumber, from + span - 1) });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
finish(e instanceof Error ? e : new Error('captcha: worker failed'));
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const b64url = (text) => {
|
|
171
|
+
const bytes = new TextEncoder().encode(text);
|
|
172
|
+
let bin = '';
|
|
173
|
+
for (let i = 0; i < bytes.length; i++)
|
|
174
|
+
bin += String.fromCharCode(bytes[i]);
|
|
175
|
+
return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
176
|
+
};
|
|
177
|
+
/** Encode a solution as the `captcha_token` the flow's request carries. */
|
|
178
|
+
function encodeAtlasToken(s) {
|
|
179
|
+
return `atlas1.${b64url(JSON.stringify(s))}`;
|
|
180
|
+
}
|
|
181
|
+
/** GET a challenge from a URL (the flow's `challengeUrl`). */
|
|
182
|
+
async function fetchAtlasChallenge(url, accessible = false) {
|
|
183
|
+
const u = accessible ? `${url}${url.includes('?') ? '&' : '?'}accessible=true` : url;
|
|
184
|
+
const res = await fetch(u, { method: 'GET', credentials: 'omit' });
|
|
185
|
+
if (!res.ok)
|
|
186
|
+
throw new Error(`captcha: challenge refused (${res.status})`);
|
|
187
|
+
return (await res.json());
|
|
188
|
+
}
|
|
189
|
+
function svgImage(doc, svg) {
|
|
190
|
+
const img = doc.createElement('img');
|
|
191
|
+
// A data: image never runs script, whatever the markup.
|
|
192
|
+
img.src = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svg)))}`;
|
|
193
|
+
img.alt = '';
|
|
194
|
+
img.width = 64;
|
|
195
|
+
img.height = 64;
|
|
196
|
+
img.style.cssText = 'display:block;width:64px;height:64px;border-radius:6px';
|
|
197
|
+
return img;
|
|
198
|
+
}
|
|
199
|
+
/** Draw the shape-matching step; resolves the tile mask, or 'accessible'. */
|
|
200
|
+
function askPuzzle(box, c, labels, cancelled) {
|
|
201
|
+
const doc = box.ownerDocument;
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
box.replaceChildren();
|
|
204
|
+
const wrap = doc.createElement('div');
|
|
205
|
+
wrap.setAttribute('role', 'group');
|
|
206
|
+
wrap.setAttribute('data-atlas-captcha-puzzle', '');
|
|
207
|
+
wrap.style.cssText = 'display:flex;flex-direction:column;align-items:center;gap:8px';
|
|
208
|
+
const prompt = doc.createElement('p');
|
|
209
|
+
prompt.style.cssText = 'margin:0;font-size:13px;text-align:center';
|
|
210
|
+
prompt.textContent = labels.puzzlePrompt;
|
|
211
|
+
wrap.append(prompt, svgImage(doc, c.interactive.example));
|
|
212
|
+
const grid = doc.createElement('div');
|
|
213
|
+
grid.style.cssText = 'display:grid;grid-template-columns:repeat(3,72px);gap:6px';
|
|
214
|
+
let mask = 0;
|
|
215
|
+
c.interactive.tiles.forEach((svg, i) => {
|
|
216
|
+
const b = doc.createElement('button');
|
|
217
|
+
b.type = 'button';
|
|
218
|
+
b.setAttribute('aria-pressed', 'false');
|
|
219
|
+
b.setAttribute('aria-label', labels.tile.replace('{n}', String(i + 1)));
|
|
220
|
+
b.setAttribute('data-atlas-captcha-tile', String(i));
|
|
221
|
+
b.style.cssText = 'padding:3px;border:2px solid transparent;border-radius:8px;background:none;cursor:pointer';
|
|
222
|
+
b.append(svgImage(doc, svg));
|
|
223
|
+
b.addEventListener('click', () => {
|
|
224
|
+
mask ^= 1 << i;
|
|
225
|
+
const on = (mask & (1 << i)) !== 0;
|
|
226
|
+
b.setAttribute('aria-pressed', on ? 'true' : 'false');
|
|
227
|
+
b.style.borderColor = on ? 'currentColor' : 'transparent';
|
|
228
|
+
});
|
|
229
|
+
grid.append(b);
|
|
230
|
+
});
|
|
231
|
+
const ok = doc.createElement('button');
|
|
232
|
+
ok.type = 'button';
|
|
233
|
+
ok.setAttribute('data-atlas-captcha-confirm', '');
|
|
234
|
+
ok.textContent = labels.confirm;
|
|
235
|
+
ok.addEventListener('click', () => (cancelled() ? reject(new Error('captcha: widget removed')) : resolve(mask)));
|
|
236
|
+
wrap.append(grid, ok);
|
|
237
|
+
if (c.accessible_alternative) {
|
|
238
|
+
const alt = doc.createElement('button');
|
|
239
|
+
alt.type = 'button';
|
|
240
|
+
alt.setAttribute('data-atlas-captcha-alternative', '');
|
|
241
|
+
alt.style.cssText = 'font-size:12px;background:none;border:0;text-decoration:underline;cursor:pointer';
|
|
242
|
+
alt.textContent = labels.alternative;
|
|
243
|
+
alt.addEventListener('click', () => resolve('accessible'));
|
|
244
|
+
wrap.append(alt);
|
|
245
|
+
}
|
|
246
|
+
box.append(wrap);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/** Render Atlas's captcha into `container` and resolve the `captcha_token`. */
|
|
250
|
+
function renderAtlasCaptcha(container, opts) {
|
|
251
|
+
const labels = { ...exports.ATLAS_CAPTCHA_LABELS, ...opts.labels };
|
|
252
|
+
const mode = opts.mode ?? 'managed';
|
|
253
|
+
const doc = container.ownerDocument;
|
|
254
|
+
const fetchChallenge = opts.fetchChallenge ??
|
|
255
|
+
((accessible) => {
|
|
256
|
+
if (!opts.challengeUrl)
|
|
257
|
+
return Promise.reject(new Error('captcha: no challenge URL'));
|
|
258
|
+
return fetchAtlasChallenge(opts.challengeUrl, accessible);
|
|
259
|
+
});
|
|
260
|
+
let removed = false;
|
|
261
|
+
let expiresAt = 0;
|
|
262
|
+
const cancelled = () => removed;
|
|
263
|
+
const box = doc.createElement('div');
|
|
264
|
+
box.setAttribute('role', 'status');
|
|
265
|
+
box.setAttribute('aria-live', 'polite');
|
|
266
|
+
box.setAttribute('data-atlas-captcha-provider', 'atlas');
|
|
267
|
+
box.style.cssText = 'font-size:13px;opacity:.85;text-align:center';
|
|
268
|
+
container.append(box);
|
|
269
|
+
const say = (text) => {
|
|
270
|
+
box.replaceChildren();
|
|
271
|
+
box.textContent = text;
|
|
272
|
+
};
|
|
273
|
+
const run = async (accessible) => {
|
|
274
|
+
const c = await fetchChallenge(accessible);
|
|
275
|
+
if (removed)
|
|
276
|
+
throw new Error('captcha: widget removed');
|
|
277
|
+
expiresAt = Date.parse(c.expires_at) || 0;
|
|
278
|
+
if (mode === 'visible' || c.interactive)
|
|
279
|
+
say(labels.checking);
|
|
280
|
+
const started = Date.now();
|
|
281
|
+
const work = solveAtlasChallenge(c, { workers: opts.workers, cancelled }).then((r) => ({
|
|
282
|
+
...r,
|
|
283
|
+
ms: Date.now() - started,
|
|
284
|
+
}));
|
|
285
|
+
// A rejection here is reported by whichever await reads it.
|
|
286
|
+
work.catch(() => undefined);
|
|
287
|
+
let sel;
|
|
288
|
+
if (c.interactive) {
|
|
289
|
+
const answer = await askPuzzle(box, c, labels, cancelled);
|
|
290
|
+
if (answer === 'accessible') {
|
|
291
|
+
say(labels.checking);
|
|
292
|
+
return run(true);
|
|
293
|
+
}
|
|
294
|
+
sel = answer;
|
|
295
|
+
say(labels.checking);
|
|
296
|
+
}
|
|
297
|
+
const { n, worker, ms } = await work;
|
|
298
|
+
if (removed)
|
|
299
|
+
throw new Error('captcha: widget removed');
|
|
300
|
+
if (mode === 'visible' || sel !== undefined)
|
|
301
|
+
say(labels.verified);
|
|
302
|
+
return encodeAtlasToken({ t: c.token, n, ms, ...(worker ? { w: 1 } : {}), ...(sel !== undefined ? { sel } : {}) });
|
|
303
|
+
};
|
|
304
|
+
const token = run(false);
|
|
305
|
+
token.catch(() => undefined);
|
|
306
|
+
return {
|
|
307
|
+
token,
|
|
308
|
+
stale: () => expiresAt > 0 && Date.now() > expiresAt - 15_000,
|
|
309
|
+
remove() {
|
|
310
|
+
removed = true;
|
|
311
|
+
box.remove();
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=atlas-captcha.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas-captcha.js","sourceRoot":"","sources":["../src/atlas-captcha.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type FieldError } from './attempt';
|
|
2
2
|
import { type FapiClient, type FlowState } from './fapi';
|
|
3
|
+
import type { AtlasCaptchaLabels } from './atlas-captcha';
|
|
3
4
|
import { type FlowCaptcha } from './captcha-widget';
|
|
4
5
|
/**
|
|
5
6
|
* The captcha half of a prebuilt sign-in / sign-up form, without a framework.
|
|
@@ -43,7 +44,16 @@ export interface CaptchaController {
|
|
|
43
44
|
/** Remove the widget for good (component teardown). */
|
|
44
45
|
destroy(): void;
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
+
/** Settings that hold for the controller's whole life. */
|
|
48
|
+
export interface CaptchaControllerSettings {
|
|
49
|
+
/**
|
|
50
|
+
* The Atlas captcha's words in the form's language, read each time a widget
|
|
51
|
+
* is drawn (so a locale switch applies to the next one). See
|
|
52
|
+
* `atlasCaptchaLabels(t)`.
|
|
53
|
+
*/
|
|
54
|
+
atlasLabels?: () => Partial<AtlasCaptchaLabels>;
|
|
55
|
+
}
|
|
56
|
+
export declare function createCaptchaController(initial?: CaptchaControllerOptions, settings?: CaptchaControllerSettings): CaptchaController;
|
|
47
57
|
/**
|
|
48
58
|
* Swap the server's captcha refusals (CAPTCHA_REQUIRED / CAPTCHA_FAILED, which
|
|
49
59
|
* the server ties to the `captcha_token` param) for a localized, form-level
|
|
@@ -9,7 +9,7 @@ const attempt_1 = require("./attempt");
|
|
|
9
9
|
const fapi_1 = require("./fapi");
|
|
10
10
|
const instance_settings_1 = require("./instance-settings");
|
|
11
11
|
const captcha_widget_1 = require("./captcha-widget");
|
|
12
|
-
function createCaptchaController(initial) {
|
|
12
|
+
function createCaptchaController(initial, settings = {}) {
|
|
13
13
|
let options = initial ?? { flow: undefined, active: false };
|
|
14
14
|
let container = null;
|
|
15
15
|
let handle = null;
|
|
@@ -35,7 +35,9 @@ function createCaptchaController(initial) {
|
|
|
35
35
|
const flow = options.flow;
|
|
36
36
|
if (!needed() || !flow || !container)
|
|
37
37
|
return null;
|
|
38
|
-
const h = (0, captcha_widget_1.renderCaptchaWidget)(flow, container
|
|
38
|
+
const h = (0, captcha_widget_1.renderCaptchaWidget)(flow, container, {
|
|
39
|
+
atlas: settings.atlasLabels ? { labels: settings.atlasLabels() } : undefined,
|
|
40
|
+
});
|
|
39
41
|
handle = h;
|
|
40
42
|
drawnKey = key();
|
|
41
43
|
// Swallow here so a removed / failed widget is never an unhandled
|
|
@@ -76,7 +78,7 @@ function createCaptchaController(initial) {
|
|
|
76
78
|
if (!needed())
|
|
77
79
|
return null;
|
|
78
80
|
let h = handle;
|
|
79
|
-
if (!h || spent === h)
|
|
81
|
+
if (!h || spent === h || h.stale?.())
|
|
80
82
|
h = mount();
|
|
81
83
|
if (!h)
|
|
82
84
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"captcha-controller.js","sourceRoot":"","sources":["../src/captcha-controller.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"captcha-controller.js","sourceRoot":"","sources":["../src/captcha-controller.ts"],"names":[],"mappings":"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"}
|
package/dist/captcha-widget.d.ts
CHANGED
|
@@ -18,7 +18,11 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Everything is SSR-safe: nothing touches `window`/`document` until a call that
|
|
20
20
|
* renders into a DOM element.
|
|
21
|
+
*
|
|
22
|
+
* Provider `atlas` is Atlas's own captcha: no vendor script, no site key (see
|
|
23
|
+
* `atlas-captcha.ts`).
|
|
21
24
|
*/
|
|
25
|
+
import { type AtlasCaptchaOptions } from './atlas-captcha';
|
|
22
26
|
/** The flows `captchaFlows` covers. */
|
|
23
27
|
export type CaptchaFlowKey = 'signUp' | 'signIn' | 'guest' | 'passwordReset';
|
|
24
28
|
/** How a widget-drawing provider renders. */
|
|
@@ -35,6 +39,11 @@ export interface FlowCaptcha {
|
|
|
35
39
|
provider?: string;
|
|
36
40
|
siteKey?: string | null;
|
|
37
41
|
widget?: CaptchaWidgetMode;
|
|
42
|
+
/**
|
|
43
|
+
* Provider `atlas` (Atlas's own captcha, no keys): where the widget fetches
|
|
44
|
+
* each fresh challenge. Set by `/v1/appearance`.
|
|
45
|
+
*/
|
|
46
|
+
challengeUrl?: string;
|
|
38
47
|
}
|
|
39
48
|
/** Whether the prebuilt UIs can draw this provider's widget. */
|
|
40
49
|
export declare function isRenderableCaptcha(provider?: string | null): boolean;
|
|
@@ -53,10 +62,20 @@ type Win = Window & Record<string, unknown>;
|
|
|
53
62
|
* already present (a prior load, or a test that preset it) it resolves at once.
|
|
54
63
|
*/
|
|
55
64
|
export declare function loadCaptchaProvider(provider: string, siteKey: string, win: Win): Promise<unknown>;
|
|
65
|
+
/** Per-render options. Only Atlas's own captcha reads any today. */
|
|
66
|
+
export interface RenderCaptchaOptions {
|
|
67
|
+
/** Atlas captcha: a custom challenge fetcher (e.g. through your FAPI proxy) and localised labels. */
|
|
68
|
+
atlas?: Pick<AtlasCaptchaOptions, 'fetchChallenge' | 'labels' | 'workers'>;
|
|
69
|
+
}
|
|
56
70
|
/** A widget rendered into a container: its eventual token, and a way to take it down. */
|
|
57
71
|
export interface CaptchaWidgetHandle {
|
|
58
72
|
/** Resolves with the solved token; rejects on provider error/timeout or removal. */
|
|
59
73
|
token: Promise<string>;
|
|
74
|
+
/**
|
|
75
|
+
* True when the solved token is about to expire unspent (Atlas's captcha), so
|
|
76
|
+
* the caller draws a fresh widget instead of sending it. Absent: never stale.
|
|
77
|
+
*/
|
|
78
|
+
stale?(): boolean;
|
|
60
79
|
/**
|
|
61
80
|
* Remove the widget (provider teardown + empty the container). Tokens are
|
|
62
81
|
* single-use, so call this after a submit spent the token and render a fresh
|
|
@@ -70,12 +89,12 @@ export interface CaptchaWidgetHandle {
|
|
|
70
89
|
* `container` is where a visible/managed widget draws; score providers draw
|
|
71
90
|
* nothing there.
|
|
72
91
|
*/
|
|
73
|
-
export declare function renderCaptchaWidget(flow: FlowCaptcha, container: HTMLElement): CaptchaWidgetHandle;
|
|
92
|
+
export declare function renderCaptchaWidget(flow: FlowCaptcha, container: HTMLElement, options?: RenderCaptchaOptions): CaptchaWidgetHandle;
|
|
74
93
|
/**
|
|
75
94
|
* Obtain a captcha token for a flow: render the widget into `container` and
|
|
76
95
|
* resolve its token. Rejects on provider error/timeout — the caller decides
|
|
77
96
|
* whether to surface it or let the (fail-closed) server reject the tokenless
|
|
78
97
|
* request.
|
|
79
98
|
*/
|
|
80
|
-
export declare function getCaptchaToken(flow: FlowCaptcha, container: HTMLElement): Promise<string>;
|
|
99
|
+
export declare function getCaptchaToken(flow: FlowCaptcha, container: HTMLElement, options?: RenderCaptchaOptions): Promise<string>;
|
|
81
100
|
export {};
|