@plitzi/sdk-auth 0.37.2 → 0.37.3
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 +1151 -0
- package/dist/AuthContextProvider.mjs +80 -64
- package/dist/AuthManager.mjs +8 -7
- package/dist/AuthProvider.d.ts +12 -2
- package/dist/AuthProvider.mjs +9 -7
- package/dist/helpers/publishedSession.d.ts +31 -0
- package/dist/helpers/publishedSession.mjs +16 -0
- package/dist/providers/BasicAuthProvider.d.ts +9 -3
- package/dist/providers/BasicAuthProvider.mjs +30 -8
- package/dist/providers/ServerAuthProvider.d.ts +41 -0
- package/dist/providers/ServerAuthProvider.mjs +46 -0
- package/dist/types.d.ts +1 -1
- package/package.json +15 -7
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { AuthContext as e } from "./AuthContext.mjs";
|
|
2
|
-
import t from "./
|
|
3
|
-
import n from "./hooks/
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import s from "@plitzi/
|
|
7
|
-
import
|
|
8
|
-
import l from "@plitzi/sdk-shared/
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
2
|
+
import { publishedSession as t } from "./helpers/publishedSession.mjs";
|
|
3
|
+
import n from "./hooks/useAuth/index.mjs";
|
|
4
|
+
import r from "./hooks/useSessionQueryReset/index.mjs";
|
|
5
|
+
import { use as i, useMemo as a, useRef as o } from "react";
|
|
6
|
+
import { QueryBuilderEvaluator as s } from "@plitzi/plitzi-ui/QueryBuilder";
|
|
7
|
+
import c from "@plitzi/sdk-navigation/hooks/useNavigation";
|
|
8
|
+
import { processTwig as l } from "@plitzi/sdk-shared/helpers/twigWrapper";
|
|
9
|
+
import u from "@plitzi/sdk-shared/network/NetworkContext";
|
|
10
|
+
import { useCommonStore as d, useRenderSettings as f } from "@plitzi/sdk-shared/store";
|
|
11
|
+
import { jsx as p } from "react/jsx-runtime";
|
|
11
12
|
//#region src/AuthContextProvider.tsx
|
|
12
|
-
var
|
|
13
|
+
var m = [
|
|
13
14
|
"loginUrl",
|
|
14
15
|
"userUrl",
|
|
15
16
|
"refreshUrl",
|
|
@@ -20,28 +21,29 @@ var p = [
|
|
|
20
21
|
"expirationTimePath",
|
|
21
22
|
"refreshExpirationTimePath",
|
|
22
23
|
"sessionHintCookie",
|
|
23
|
-
"sessionExchangeUrl"
|
|
24
|
-
|
|
24
|
+
"sessionExchangeUrl",
|
|
25
|
+
"mfaUrl"
|
|
26
|
+
], h = (e, t) => {
|
|
25
27
|
if (e === t) return !0;
|
|
26
28
|
if (!e || !t) return !1;
|
|
27
29
|
let n = e, r = t;
|
|
28
30
|
return [.../* @__PURE__ */ new Set([...Object.keys(n), ...Object.keys(r)])].every((e) => JSON.stringify(n[e]) === JSON.stringify(r[e]));
|
|
29
|
-
},
|
|
30
|
-
let { previewMode:
|
|
31
|
-
queryParams:
|
|
32
|
-
hostname:
|
|
33
|
-
environment:
|
|
31
|
+
}, g = ({ children: g, server: _ }) => {
|
|
32
|
+
let { previewMode: v, isHydrating: y, environment: b } = f(), { webKey: x } = i(u), [[S, C]] = d(["schema.settings", "schema.variables"]), { queryParams: w, hostname: T } = c({ server: _ }), E = a(() => ({
|
|
33
|
+
queryParams: w,
|
|
34
|
+
hostname: T,
|
|
35
|
+
environment: b
|
|
34
36
|
}), [
|
|
35
|
-
C,
|
|
36
37
|
w,
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
T,
|
|
39
|
+
b
|
|
40
|
+
]), D = a(() => Array.isArray(C) ? C.reduce((e, t) => {
|
|
39
41
|
let { name: n, value: r, subValues: i } = t;
|
|
40
42
|
if (!Array.isArray(i) || i.length === 0) return {
|
|
41
43
|
...e,
|
|
42
44
|
[n]: r
|
|
43
45
|
};
|
|
44
|
-
let a = i.find((e) =>
|
|
46
|
+
let a = i.find((e) => s(e.when, E));
|
|
45
47
|
return a ? {
|
|
46
48
|
...e,
|
|
47
49
|
[n]: a.value
|
|
@@ -49,57 +51,71 @@ var p = [
|
|
|
49
51
|
...e,
|
|
50
52
|
[n]: r
|
|
51
53
|
};
|
|
52
|
-
}, {}) : {}, [
|
|
53
|
-
let e = Object.fromEntries(
|
|
54
|
+
}, {}) : {}, [C, E]), O = a(() => {
|
|
55
|
+
let e = Object.fromEntries(m.map((e) => [e, S[e]]));
|
|
54
56
|
try {
|
|
55
|
-
return JSON.parse(
|
|
57
|
+
return JSON.parse(l(JSON.stringify(e), D));
|
|
56
58
|
} catch {
|
|
57
59
|
return e;
|
|
58
60
|
}
|
|
59
|
-
}, [
|
|
60
|
-
...
|
|
61
|
-
spaceKey:
|
|
62
|
-
tokenStorage:
|
|
63
|
-
sessionGate:
|
|
64
|
-
sessionRevalidateSeconds:
|
|
61
|
+
}, [S, D]), k = a(() => ({
|
|
62
|
+
...O,
|
|
63
|
+
spaceKey: x,
|
|
64
|
+
tokenStorage: S.tokenStorage ?? "localStorage",
|
|
65
|
+
sessionGate: S.sessionGate,
|
|
66
|
+
sessionRevalidateSeconds: S.sessionRevalidateSeconds
|
|
65
67
|
}), [
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
]), { manager:
|
|
70
|
-
server:
|
|
71
|
-
isHydrating:
|
|
72
|
-
provider:
|
|
73
|
-
settings:
|
|
74
|
-
}),
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
68
|
+
O,
|
|
69
|
+
S,
|
|
70
|
+
x
|
|
71
|
+
]), { manager: A, loading: j, authenticated: M, state: N, bootstrapUser: P, bootstrapToken: F, peekedUser: I, peekedToken: L } = n({
|
|
72
|
+
server: _,
|
|
73
|
+
isHydrating: y,
|
|
74
|
+
provider: S.userProvider ?? "",
|
|
75
|
+
settings: k
|
|
76
|
+
}), R = A.getProvider(), { user: z, accessToken: B } = t({
|
|
77
|
+
state: N,
|
|
78
|
+
provider: {
|
|
79
|
+
user: R?.user,
|
|
80
|
+
accessToken: R?.token?.accessToken
|
|
81
|
+
},
|
|
82
|
+
bootstrap: {
|
|
83
|
+
user: P,
|
|
84
|
+
accessToken: F
|
|
85
|
+
},
|
|
86
|
+
peeked: {
|
|
87
|
+
user: I,
|
|
88
|
+
accessToken: L
|
|
89
|
+
}
|
|
90
|
+
}), V = o(void 0), H = a(() => {
|
|
91
|
+
let e = z ? {
|
|
92
|
+
details: z,
|
|
93
|
+
accessToken: B
|
|
94
|
+
} : void 0, t = V.current;
|
|
95
|
+
return t?.accessToken === e?.accessToken && h(t?.details, e?.details) || (V.current = e), V.current;
|
|
96
|
+
}, [z, B]);
|
|
97
|
+
r(M ? String(H?.details?.id ?? "") : "");
|
|
98
|
+
let U = a(() => ({
|
|
99
|
+
login: A.login.bind(A),
|
|
100
|
+
refresh: A.refresh.bind(A),
|
|
101
|
+
revalidate: A.revalidate.bind(A),
|
|
102
|
+
invalidate: A.invalidate.bind(A),
|
|
103
|
+
can: A.can.bind(A),
|
|
104
|
+
logout: A.logout.bind(A),
|
|
105
|
+
state: N,
|
|
106
|
+
authenticated: M || !v,
|
|
107
|
+
user: H
|
|
92
108
|
}), [
|
|
93
|
-
|
|
109
|
+
A,
|
|
110
|
+
N,
|
|
94
111
|
M,
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
V
|
|
112
|
+
v,
|
|
113
|
+
H
|
|
98
114
|
]);
|
|
99
|
-
return /* @__PURE__ */
|
|
100
|
-
value:
|
|
101
|
-
children: !
|
|
115
|
+
return /* @__PURE__ */ p(e, {
|
|
116
|
+
value: U,
|
|
117
|
+
children: !j && g
|
|
102
118
|
});
|
|
103
119
|
};
|
|
104
120
|
//#endregion
|
|
105
|
-
export {
|
|
121
|
+
export { g as default };
|
package/dist/AuthManager.mjs
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import e from "./providers/BasicAuthProvider.mjs";
|
|
2
|
+
import t from "./providers/ServerAuthProvider.mjs";
|
|
2
3
|
//#region src/AuthManager.ts
|
|
3
|
-
var
|
|
4
|
-
|
|
5
|
-
},
|
|
4
|
+
var n = /* @__PURE__ */ new Map([["basic", (t) => new e(t)], ["server", (e) => new t(e)]]), r = (e, t) => {
|
|
5
|
+
n.set(e, t);
|
|
6
|
+
}, i = () => [...n.keys()], a = class {
|
|
6
7
|
providerType;
|
|
7
8
|
provider;
|
|
8
9
|
settings;
|
|
9
10
|
listeners;
|
|
10
|
-
constructor(e,
|
|
11
|
-
this.providerType = e, this.settings = r, this.listeners = Array.isArray(
|
|
12
|
-
let i =
|
|
11
|
+
constructor(e, t, r) {
|
|
12
|
+
this.providerType = e, this.settings = r, this.listeners = Array.isArray(t) ? t : [t];
|
|
13
|
+
let i = n.get(e);
|
|
13
14
|
i && (this.provider = i(r), this.provider.on(this.listeners));
|
|
14
15
|
}
|
|
15
16
|
getProviderType() {
|
|
@@ -67,4 +68,4 @@ var t = /* @__PURE__ */ new Map([["basic", (t) => new e(t)]]), n = (e, n) => {
|
|
|
67
68
|
}
|
|
68
69
|
};
|
|
69
70
|
//#endregion
|
|
70
|
-
export {
|
|
71
|
+
export { a as AuthManager, i as getAuthProviderNames, r as registerAuthProvider };
|
package/dist/AuthProvider.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthFailureReason, AuthResult, AuthState, LoginResult, Schema, TokenResult } from '@plitzi/sdk-shared';
|
|
1
|
+
import { AuthFailureReason, AuthResult, AuthState, LoginResult, MfaChallenge, Schema, TokenResult } from '@plitzi/sdk-shared';
|
|
2
2
|
/** Why a state changed. Not control flow — it is what makes an auth trace readable, and every transition below
|
|
3
3
|
* names one, because "it went to guest" is not a diagnosis and "the hint cookie was gone" is. */
|
|
4
4
|
export type AuthStateReason = 'bootstrap' | 'restored' | 'granted' | 'renewed' | 'identity' | 'redirect' | 'exchanged' | 'no-provider' | 'skip-auth' | 'hint-missing' | 'no-evidence' | 'signed-out' | 'another-tab' | 'settled' | 'authenticating';
|
|
@@ -52,6 +52,15 @@ declare abstract class AuthProvider<U = Record<string, unknown>> {
|
|
|
52
52
|
private readonly revalidateSeconds;
|
|
53
53
|
private readonly listeners;
|
|
54
54
|
private renewal?;
|
|
55
|
+
/**
|
|
56
|
+
* Which session an answer belongs to. Moved on by every change of WHO is signed in — a sign-out, a sign-in, another
|
|
57
|
+
* tab's — and read around each request that can adopt or end a session.
|
|
58
|
+
*
|
|
59
|
+
* An identity asked for before a sign-out and answered after it carried the old cookie, so it came back `ok` and
|
|
60
|
+
* signed the person straight back in: the router then read a session on the guest's own page and answered "Access
|
|
61
|
+
* Denied". Under load that is not a corner case — the account screen asks who is there while its button is pressed.
|
|
62
|
+
*/
|
|
63
|
+
private epoch;
|
|
55
64
|
private renewalTimer?;
|
|
56
65
|
private detachListeners?;
|
|
57
66
|
/** Set when a request failed to reach the backend, so the next `online` event retries instead of waiting. */
|
|
@@ -65,7 +74,8 @@ declare abstract class AuthProvider<U = Record<string, unknown>> {
|
|
|
65
74
|
/** The backend's endpoints. Refusals reported from elsewhere are matched against these, so a session only reacts
|
|
66
75
|
* to the API that issued it. Empty means "unknown", and then every refusal is taken as ours. */
|
|
67
76
|
protected get endpoints(): string[];
|
|
68
|
-
|
|
77
|
+
/** A session, why there is none — or, for an account with a second factor, the challenge its code completes. */
|
|
78
|
+
protected abstract requestLogin(params: Record<string, unknown>): Promise<AuthResult<U> | MfaChallenge>;
|
|
69
79
|
protected abstract requestRenewal(refreshToken?: string): Promise<AuthResult<U>>;
|
|
70
80
|
protected abstract requestIdentity(): Promise<AuthResult<U>>;
|
|
71
81
|
protected abstract requestLogout(): Promise<void>;
|
package/dist/AuthProvider.mjs
CHANGED
|
@@ -12,6 +12,7 @@ var s = 60, c = 300, l = 2147483647, u = class {
|
|
|
12
12
|
revalidateSeconds;
|
|
13
13
|
listeners = /* @__PURE__ */ new Set();
|
|
14
14
|
renewal;
|
|
15
|
+
epoch = 0;
|
|
15
16
|
renewalTimer;
|
|
16
17
|
detachListeners;
|
|
17
18
|
offline = !1;
|
|
@@ -126,8 +127,9 @@ var s = 60, c = 300, l = 2147483647, u = class {
|
|
|
126
127
|
clearTimeout(this.renewalTimer), this.renewalTimer = void 0, this.detachListeners?.(), this.detachListeners = void 0;
|
|
127
128
|
}
|
|
128
129
|
async login(e) {
|
|
129
|
-
this.setState("authenticating", "authenticating");
|
|
130
|
+
this.epoch += 1, this.setState("authenticating", "authenticating");
|
|
130
131
|
let t = await this.requestLogin(e);
|
|
132
|
+
if (!t.ok && t.reason === "mfa") return this.endSession(), t;
|
|
131
133
|
if (!t.ok) return this.endSession(t.reason), {
|
|
132
134
|
ok: !1,
|
|
133
135
|
reason: t.reason
|
|
@@ -206,12 +208,12 @@ var s = 60, c = 300, l = 2147483647, u = class {
|
|
|
206
208
|
}), this.renewal;
|
|
207
209
|
}
|
|
208
210
|
async performRenewal() {
|
|
209
|
-
let e = await this.requestRenewal(this.session.token?.refreshToken ?? void 0);
|
|
210
|
-
return e.ok ? (this.adopt(
|
|
211
|
+
let e = this.epoch, t = await this.requestRenewal(this.session.token?.refreshToken ?? void 0);
|
|
212
|
+
return e === this.epoch ? t.ok ? (this.adopt(t), !this.session.user && this.capabilities.identity ? this.loadIdentity() : this.state === "authenticated") : (this.handleFailure(t.reason), !1) : this.state === "authenticated";
|
|
211
213
|
}
|
|
212
214
|
async loadIdentity() {
|
|
213
|
-
let e = await this.requestIdentity();
|
|
214
|
-
return e.ok ? (this.adopt(
|
|
215
|
+
let e = this.epoch, t = await this.requestIdentity();
|
|
216
|
+
return e === this.epoch ? t.ok ? (this.adopt(t), this.state === "authenticated") : t.reason === "expired" && this.capabilities.renew && !this.renewal ? this.renew() : (this.handleFailure(t.reason), !1) : this.state === "authenticated";
|
|
215
217
|
}
|
|
216
218
|
handleFailure(e) {
|
|
217
219
|
if (e === "network") {
|
|
@@ -228,7 +230,7 @@ var s = 60, c = 300, l = 2147483647, u = class {
|
|
|
228
230
|
}, this.offline = !1, t && this.store.write(this.session), this.scheduleRenewal(), this.setState(this.session.user || this.hasLiveToken() ? "authenticated" : "guest", r);
|
|
229
231
|
}
|
|
230
232
|
endSession(e, t = "signed-out") {
|
|
231
|
-
clearTimeout(this.renewalTimer), this.renewalTimer = void 0, this.session = { validatedAt: n() }, this.store.write(this.session), this.setState("guest", t), e && this.emit({
|
|
233
|
+
this.epoch += 1, clearTimeout(this.renewalTimer), this.renewalTimer = void 0, this.session = { validatedAt: n() }, this.store.write(this.session), this.setState("guest", t), e && this.emit({
|
|
232
234
|
type: "expired",
|
|
233
235
|
reason: e
|
|
234
236
|
});
|
|
@@ -282,7 +284,7 @@ var s = 60, c = 300, l = 2147483647, u = class {
|
|
|
282
284
|
};
|
|
283
285
|
}
|
|
284
286
|
adoptFromStorage(e) {
|
|
285
|
-
if (!e?.token && !e?.user) {
|
|
287
|
+
if (this.epoch += 1, !e?.token && !e?.user) {
|
|
286
288
|
clearTimeout(this.renewalTimer), this.renewalTimer = void 0, this.session = { validatedAt: n() }, this.setState("guest", "another-tab"), this.emit({ type: "logout" });
|
|
287
289
|
return;
|
|
288
290
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AuthState } from '@plitzi/sdk-shared';
|
|
2
|
+
/**
|
|
3
|
+
* Who the page says is signed in, from what is known about them at this moment.
|
|
4
|
+
*
|
|
5
|
+
* The provider is authoritative once it has settled. Before that — the first commit of a server-rendered page, a reload
|
|
6
|
+
* with a session in storage — it holds nothing yet, and the page falls back to what it already knows: the user the
|
|
7
|
+
* server rendered with (`bootstrap`), then the one peeked from storage (`peeked`).
|
|
8
|
+
*
|
|
9
|
+
* Only before. Once the provider says `guest` there is nobody, whatever the page was rendered with: the fallback used
|
|
10
|
+
* to outlive a sign-out, so the page went on publishing the previous person and every flow that asked "is anybody
|
|
11
|
+
* signed in?" was told yes — a sign-in screen that sends signed-in visitors to their account sent this one there, the
|
|
12
|
+
* account (rightly) sent them back, and the two bounced off each other hundreds of times a second.
|
|
13
|
+
*/
|
|
14
|
+
export declare const publishedSession: <U>(input: {
|
|
15
|
+
state: AuthState;
|
|
16
|
+
provider?: {
|
|
17
|
+
user?: U;
|
|
18
|
+
accessToken?: string;
|
|
19
|
+
};
|
|
20
|
+
bootstrap?: {
|
|
21
|
+
user?: U;
|
|
22
|
+
accessToken?: string;
|
|
23
|
+
};
|
|
24
|
+
peeked?: {
|
|
25
|
+
user?: U;
|
|
26
|
+
accessToken?: string;
|
|
27
|
+
};
|
|
28
|
+
}) => {
|
|
29
|
+
user?: U;
|
|
30
|
+
accessToken?: string;
|
|
31
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/helpers/publishedSession.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
let { state: t, provider: n, bootstrap: r, peeked: i } = e;
|
|
4
|
+
return n?.user ? {
|
|
5
|
+
user: n.user,
|
|
6
|
+
accessToken: n.accessToken
|
|
7
|
+
} : t === "guest" ? {} : r?.user ? {
|
|
8
|
+
user: r.user,
|
|
9
|
+
accessToken: r.accessToken
|
|
10
|
+
} : i?.user ? {
|
|
11
|
+
user: i.user,
|
|
12
|
+
accessToken: i.accessToken
|
|
13
|
+
} : {};
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { e as publishedSession };
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { default as AuthProvider, AuthProviderProps } from '../AuthProvider';
|
|
2
|
-
import { AuthResult, Schema } from '@plitzi/sdk-shared';
|
|
2
|
+
import { AuthResult, MfaChallenge, Schema } from '@plitzi/sdk-shared';
|
|
3
3
|
export type BasicAuthProviderProps = AuthProviderProps & {
|
|
4
4
|
loginUrl?: string;
|
|
5
5
|
userUrl?: string;
|
|
6
6
|
refreshUrl?: string;
|
|
7
7
|
logoutUrl?: string;
|
|
8
8
|
sessionExchangeUrl?: Schema['settings']['sessionExchangeUrl'];
|
|
9
|
+
mfaUrl?: Schema['settings']['mfaUrl'];
|
|
9
10
|
detailsPath?: Schema['settings']['detailsPath'];
|
|
10
11
|
tokenPath?: Schema['settings']['tokenPath'];
|
|
11
12
|
refreshTokenPath?: Schema['settings']['refreshTokenPath'];
|
|
@@ -15,7 +16,7 @@ export type BasicAuthProviderProps = AuthProviderProps & {
|
|
|
15
16
|
declare class BasicAuthProvider<U = Record<string, unknown>> extends AuthProvider<U> {
|
|
16
17
|
readonly name = "basic";
|
|
17
18
|
private readonly options;
|
|
18
|
-
constructor({ loginUrl, userUrl, refreshUrl, logoutUrl, sessionExchangeUrl, detailsPath, tokenPath, refreshTokenPath, expirationTimePath, refreshExpirationTimePath, ...providerProps }?: BasicAuthProviderProps);
|
|
19
|
+
constructor({ loginUrl, userUrl, refreshUrl, logoutUrl, sessionExchangeUrl, mfaUrl, detailsPath, tokenPath, refreshTokenPath, expirationTimePath, refreshExpirationTimePath, ...providerProps }?: BasicAuthProviderProps);
|
|
19
20
|
protected get capabilities(): {
|
|
20
21
|
renew: boolean;
|
|
21
22
|
identity: boolean;
|
|
@@ -29,7 +30,7 @@ declare class BasicAuthProvider<U = Record<string, unknown>> extends AuthProvide
|
|
|
29
30
|
* taken on trust: an unusable token is refused here rather than becoming a session that fails on its first real
|
|
30
31
|
* request. `mode: 'normal'` (the default) posts the credentials.
|
|
31
32
|
*/
|
|
32
|
-
protected requestLogin(params: Record<string, unknown>): Promise<AuthResult<U
|
|
33
|
+
protected requestLogin(params: Record<string, unknown>): Promise<AuthResult<U> | MfaChallenge>;
|
|
33
34
|
/** Confirms a token by asking who it belongs to, and only then reports it as a session. */
|
|
34
35
|
private adoptToken;
|
|
35
36
|
/**
|
|
@@ -46,6 +47,11 @@ declare class BasicAuthProvider<U = Record<string, unknown>> extends AuthProvide
|
|
|
46
47
|
protected requestIdentity(): Promise<AuthResult<U>>;
|
|
47
48
|
protected requestLogout(): Promise<void>;
|
|
48
49
|
private request;
|
|
50
|
+
/**
|
|
51
|
+
* A right password on an account with a second factor: a challenge, not a session with nobody in it. Read as the
|
|
52
|
+
* latter it ended as `inactive`, and told somebody with a perfectly good account that it could not be used.
|
|
53
|
+
*/
|
|
54
|
+
private challengeOf;
|
|
49
55
|
private toResult;
|
|
50
56
|
private tokenFrom;
|
|
51
57
|
}
|
|
@@ -11,18 +11,19 @@ var r = (e, n) => t(e, n, void 0), i = (e, t) => {
|
|
|
11
11
|
}, o = (e) => typeof e == "string" ? e : typeof e == "number" && Number.isFinite(e) ? String(e) : "", s = class extends e {
|
|
12
12
|
name = "basic";
|
|
13
13
|
options;
|
|
14
|
-
constructor({ loginUrl: e = "", userUrl: t = "", refreshUrl: n = "", logoutUrl: r = "", sessionExchangeUrl: i = "",
|
|
15
|
-
super(
|
|
14
|
+
constructor({ loginUrl: e = "", userUrl: t = "", refreshUrl: n = "", logoutUrl: r = "", sessionExchangeUrl: i = "", mfaUrl: a = "", detailsPath: o = "details", tokenPath: s = "access_token", refreshTokenPath: c = "refresh_token", expirationTimePath: l = "expire_at", refreshExpirationTimePath: u = "refresh_expire_at", ...d } = {}) {
|
|
15
|
+
super(d), this.options = {
|
|
16
16
|
loginUrl: e,
|
|
17
17
|
userUrl: t,
|
|
18
18
|
refreshUrl: n,
|
|
19
19
|
logoutUrl: r,
|
|
20
20
|
sessionExchangeUrl: i,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
mfaUrl: a,
|
|
22
|
+
detailsPath: o,
|
|
23
|
+
tokenPath: s,
|
|
24
|
+
refreshTokenPath: c,
|
|
25
|
+
expirationTimePath: l,
|
|
26
|
+
refreshExpirationTimePath: u
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
get capabilities() {
|
|
@@ -46,6 +47,19 @@ var r = (e, n) => t(e, n, void 0), i = (e, t) => {
|
|
|
46
47
|
ok: !1,
|
|
47
48
|
reason: "missing"
|
|
48
49
|
};
|
|
50
|
+
if (e.mode === "mfa") {
|
|
51
|
+
let t = o(e.mfaToken).trim();
|
|
52
|
+
return !this.options.mfaUrl || !t ? {
|
|
53
|
+
ok: !1,
|
|
54
|
+
reason: "missing"
|
|
55
|
+
} : this.toResult(await this.request(this.options.mfaUrl, {
|
|
56
|
+
method: "POST",
|
|
57
|
+
body: JSON.stringify({
|
|
58
|
+
mfaToken: t,
|
|
59
|
+
code: o(e.code).trim()
|
|
60
|
+
})
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
49
63
|
if (!this.options.loginUrl) return {
|
|
50
64
|
ok: !1,
|
|
51
65
|
reason: "missing"
|
|
@@ -57,7 +71,7 @@ var r = (e, n) => t(e, n, void 0), i = (e, t) => {
|
|
|
57
71
|
password: o(e.password)
|
|
58
72
|
})
|
|
59
73
|
});
|
|
60
|
-
return this.toResult(n);
|
|
74
|
+
return this.challengeOf(n) ?? this.toResult(n);
|
|
61
75
|
}
|
|
62
76
|
async adoptToken(e) {
|
|
63
77
|
if (!this.options.userUrl) return {
|
|
@@ -145,6 +159,14 @@ var r = (e, n) => t(e, n, void 0), i = (e, t) => {
|
|
|
145
159
|
reason: r.ok ? void 0 : n(r.status, i) ?? "network"
|
|
146
160
|
};
|
|
147
161
|
}
|
|
162
|
+
challengeOf(e) {
|
|
163
|
+
let t = r(e.data, "mfaToken");
|
|
164
|
+
return !e.reason && r(e.data, "mfaRequired") === !0 && typeof t == "string" && t ? {
|
|
165
|
+
ok: !1,
|
|
166
|
+
reason: "mfa",
|
|
167
|
+
mfaToken: t
|
|
168
|
+
} : void 0;
|
|
169
|
+
}
|
|
148
170
|
toResult(e) {
|
|
149
171
|
if (e.reason) return {
|
|
150
172
|
ok: !1,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { default as AuthProvider, AuthProviderProps } from '../AuthProvider';
|
|
2
|
+
import { AuthResult, MfaChallenge } from '@plitzi/sdk-shared';
|
|
3
|
+
export type ServerAuthProviderProps = AuthProviderProps & {
|
|
4
|
+
/** Where the page server starts a sign-in by redirect. Default `/auth/sign-in` (`createServer({ signIn })`). */
|
|
5
|
+
loginUrl?: string;
|
|
6
|
+
/** Where the page server ends the session on its host. Default `/auth/logout`. */
|
|
7
|
+
logoutUrl?: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* A space whose people sign in THROUGH the server that renders it: signing in is a redirect out and back
|
|
11
|
+
* (`createServer({ signIn })` — "Sign in with Plitzi" on the platform), and the session is a cookie on the space's
|
|
12
|
+
* own host that the page never holds.
|
|
13
|
+
*
|
|
14
|
+
* So there is nothing here to store, renew or ask about. Who is signed in is what the server rendered the page for —
|
|
15
|
+
* it resolves the visitor on every request and hands the answer over with the page — and it is the server that ends a
|
|
16
|
+
* session. What this provider does is the two things only a browser can: go and sign in, and ask to sign out.
|
|
17
|
+
*/
|
|
18
|
+
declare class ServerAuthProvider<U = Record<string, unknown>> extends AuthProvider<U> {
|
|
19
|
+
readonly name = "server";
|
|
20
|
+
private readonly loginUrl;
|
|
21
|
+
private readonly logoutUrl;
|
|
22
|
+
constructor({ loginUrl, logoutUrl, ...providerProps }?: ServerAuthProviderProps);
|
|
23
|
+
protected get capabilities(): {
|
|
24
|
+
renew: boolean;
|
|
25
|
+
identity: boolean;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Off to sign in, and back to this very page. The promise never settles: the page is being left, and whatever it
|
|
29
|
+
* said next would be said to nobody.
|
|
30
|
+
*/
|
|
31
|
+
protected requestLogin(): Promise<AuthResult<U> | MfaChallenge>;
|
|
32
|
+
protected requestRenewal(): Promise<AuthResult<U>>;
|
|
33
|
+
protected requestIdentity(): Promise<AuthResult<U>>;
|
|
34
|
+
protected requestLogout(): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Nothing to confirm from here: the page cannot see its own session, and the server answers who is signed in on
|
|
37
|
+
* every page it serves. The session stands as the server rendered it until the server says otherwise.
|
|
38
|
+
*/
|
|
39
|
+
revalidate(): Promise<boolean>;
|
|
40
|
+
}
|
|
41
|
+
export default ServerAuthProvider;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import e from "../AuthProvider.mjs";
|
|
2
|
+
//#region src/providers/ServerAuthProvider.ts
|
|
3
|
+
var t = class extends e {
|
|
4
|
+
name = "server";
|
|
5
|
+
loginUrl;
|
|
6
|
+
logoutUrl;
|
|
7
|
+
constructor({ loginUrl: e = "", logoutUrl: t = "", ...n } = {}) {
|
|
8
|
+
super({
|
|
9
|
+
...n,
|
|
10
|
+
tokenStorage: ""
|
|
11
|
+
}), this.loginUrl = e || "/auth/sign-in", this.logoutUrl = t || "/auth/logout";
|
|
12
|
+
}
|
|
13
|
+
get capabilities() {
|
|
14
|
+
return {
|
|
15
|
+
renew: !1,
|
|
16
|
+
identity: !1
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
requestLogin() {
|
|
20
|
+
let e = `${window.location.pathname}${window.location.search}`;
|
|
21
|
+
return window.location.assign(`${this.loginUrl}?return=${encodeURIComponent(e)}`), new Promise(() => void 0);
|
|
22
|
+
}
|
|
23
|
+
requestRenewal() {
|
|
24
|
+
return Promise.resolve({
|
|
25
|
+
ok: !1,
|
|
26
|
+
reason: "expired"
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
requestIdentity() {
|
|
30
|
+
return Promise.resolve({
|
|
31
|
+
ok: !1,
|
|
32
|
+
reason: "missing"
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async requestLogout() {
|
|
36
|
+
await fetch(this.logoutUrl, {
|
|
37
|
+
method: "POST",
|
|
38
|
+
credentials: "same-origin"
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
revalidate() {
|
|
42
|
+
return Promise.resolve(this.getState() === "authenticated");
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
export { t as default };
|
package/dist/types.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ import { Schema } from '@plitzi/sdk-shared';
|
|
|
3
3
|
* Everything a space declares about its auth backend, handed to whichever provider it selected. Derived from the
|
|
4
4
|
* schema rather than restated, so a setting added there reaches providers without a second definition to keep in step.
|
|
5
5
|
*/
|
|
6
|
-
export type AuthProviderSettings = Pick<Schema['settings'], 'tokenStorage' | 'loginUrl' | 'userUrl' | 'refreshUrl' | 'logoutUrl' | 'detailsPath' | 'tokenPath' | 'refreshTokenPath' | 'expirationTimePath' | 'refreshExpirationTimePath' | 'sessionHintCookie' | 'sessionExchangeUrl' | 'sessionGate' | 'sessionRevalidateSeconds'>;
|
|
6
|
+
export type AuthProviderSettings = Pick<Schema['settings'], 'tokenStorage' | 'loginUrl' | 'userUrl' | 'refreshUrl' | 'logoutUrl' | 'detailsPath' | 'tokenPath' | 'refreshTokenPath' | 'expirationTimePath' | 'refreshExpirationTimePath' | 'sessionHintCookie' | 'sessionExchangeUrl' | 'mfaUrl' | 'sessionGate' | 'sessionRevalidateSeconds'>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plitzi/sdk-auth",
|
|
3
|
-
"version": "0.37.
|
|
3
|
+
"version": "0.37.3",
|
|
4
4
|
"license": "AGPL-3.0",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
"types": "./dist/helpers/SessionStore.d.ts",
|
|
31
31
|
"import": "./dist/helpers/SessionStore.mjs"
|
|
32
32
|
},
|
|
33
|
+
"./helpers/publishedSession": {
|
|
34
|
+
"types": "./dist/helpers/publishedSession.d.ts",
|
|
35
|
+
"import": "./dist/helpers/publishedSession.mjs"
|
|
36
|
+
},
|
|
33
37
|
"./helpers/sessionHint": {
|
|
34
38
|
"types": "./dist/helpers/sessionHint.d.ts",
|
|
35
39
|
"import": "./dist/helpers/sessionHint.mjs"
|
|
@@ -70,6 +74,10 @@
|
|
|
70
74
|
"types": "./dist/providers/BasicAuthProvider.d.ts",
|
|
71
75
|
"import": "./dist/providers/BasicAuthProvider.mjs"
|
|
72
76
|
},
|
|
77
|
+
"./providers/ServerAuthProvider": {
|
|
78
|
+
"types": "./dist/providers/ServerAuthProvider.d.ts",
|
|
79
|
+
"import": "./dist/providers/ServerAuthProvider.mjs"
|
|
80
|
+
},
|
|
73
81
|
"./types": {
|
|
74
82
|
"types": "./dist/types.d.ts"
|
|
75
83
|
}
|
|
@@ -87,16 +95,16 @@
|
|
|
87
95
|
"build:prod": "vite build && node ../sdk-shared/scripts/generate-exports.mjs"
|
|
88
96
|
},
|
|
89
97
|
"dependencies": {
|
|
90
|
-
"@plitzi/nexus": "^1.
|
|
91
|
-
"@plitzi/plitzi-ui": "^1.6.
|
|
92
|
-
"@plitzi/sdk-navigation": "0.37.
|
|
93
|
-
"@plitzi/sdk-schema": "0.37.
|
|
94
|
-
"@plitzi/sdk-shared": "0.37.
|
|
98
|
+
"@plitzi/nexus": "^1.3.1",
|
|
99
|
+
"@plitzi/plitzi-ui": "^1.6.24",
|
|
100
|
+
"@plitzi/sdk-navigation": "0.37.3",
|
|
101
|
+
"@plitzi/sdk-schema": "0.37.3",
|
|
102
|
+
"@plitzi/sdk-shared": "0.37.3"
|
|
95
103
|
},
|
|
96
104
|
"devDependencies": {
|
|
97
105
|
"eslint": "^9.39.5",
|
|
98
106
|
"typescript": "^6.0.3",
|
|
99
|
-
"vite": "^8.3.
|
|
107
|
+
"vite": "^8.3.1",
|
|
100
108
|
"vitest": "^5.0.1"
|
|
101
109
|
}
|
|
102
110
|
}
|