@c9up/warden 0.1.21 → 0.1.23
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/README.md +1 -1
- package/dist/AuthManager.d.ts +14 -3
- package/dist/AuthManager.d.ts.map +1 -1
- package/dist/AuthManager.js +32 -4
- package/dist/AuthManager.js.map +1 -1
- package/dist/Authenticator.d.ts +48 -4
- package/dist/Authenticator.d.ts.map +1 -1
- package/dist/Authenticator.js +234 -25
- package/dist/Authenticator.js.map +1 -1
- package/dist/config.d.ts +8 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/middleware.d.ts +13 -0
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js.map +1 -1
- package/dist/native/generated.d.ts +8 -0
- package/dist/native/generated.d.ts.map +1 -0
- package/dist/native/generated.js +7 -0
- package/dist/native/generated.js.map +1 -0
- package/dist/native.d.ts +8 -9
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/strategies/SessionStrategy.d.ts +37 -25
- package/dist/strategies/SessionStrategy.d.ts.map +1 -1
- package/dist/strategies/SessionStrategy.js +43 -44
- package/dist/strategies/SessionStrategy.js.map +1 -1
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +3 -2
- package/scripts/build-napi-types.mjs +68 -0
- package/scripts/generate-napi-types.mjs +153 -0
- package/src/AuthManager.ts +68 -6
- package/src/Authenticator.ts +298 -27
- package/src/config.ts +8 -1
- package/src/index.ts +9 -11
- package/src/middleware.ts +17 -0
- package/src/native/generated.ts +23 -0
- package/src/native.ts +8 -9
- package/src/strategies/SessionStrategy.ts +73 -46
- package/dist/firstcontact/FirstContactManager.d.ts +0 -25
- package/dist/firstcontact/FirstContactManager.d.ts.map +0 -1
- package/dist/firstcontact/FirstContactManager.js +0 -38
- package/dist/firstcontact/FirstContactManager.js.map +0 -1
- package/dist/firstcontact/drivers/GitHubDriver.d.ts +0 -14
- package/dist/firstcontact/drivers/GitHubDriver.d.ts.map +0 -1
- package/dist/firstcontact/drivers/GitHubDriver.js +0 -60
- package/dist/firstcontact/drivers/GitHubDriver.js.map +0 -1
- package/dist/firstcontact/drivers/GoogleDriver.d.ts +0 -14
- package/dist/firstcontact/drivers/GoogleDriver.d.ts.map +0 -1
- package/dist/firstcontact/drivers/GoogleDriver.js +0 -63
- package/dist/firstcontact/drivers/GoogleDriver.js.map +0 -1
- package/dist/firstcontact/types.d.ts +0 -44
- package/dist/firstcontact/types.d.ts.map +0 -1
- package/dist/firstcontact/types.js +0 -22
- package/dist/firstcontact/types.js.map +0 -1
- package/src/firstcontact/FirstContactManager.ts +0 -54
- package/src/firstcontact/drivers/GitHubDriver.ts +0 -77
- package/src/firstcontact/drivers/GoogleDriver.ts +0 -80
- package/src/firstcontact/types.ts +0 -62
package/src/index.ts
CHANGED
|
@@ -44,7 +44,10 @@ export type {
|
|
|
44
44
|
BouncerEmitter,
|
|
45
45
|
PolicyContainerResolver,
|
|
46
46
|
} from "./bouncer/types.js";
|
|
47
|
-
export type {
|
|
47
|
+
export type {
|
|
48
|
+
GuardFactory,
|
|
49
|
+
WardenConfig,
|
|
50
|
+
} from "./config.js";
|
|
48
51
|
export {
|
|
49
52
|
apiKeyGuard,
|
|
50
53
|
basicAuthGuard,
|
|
@@ -58,15 +61,6 @@ export {
|
|
|
58
61
|
E_UNAUTHORIZED_ACCESS,
|
|
59
62
|
WardenError,
|
|
60
63
|
} from "./errors.js";
|
|
61
|
-
export { GitHubDriver } from "./firstcontact/drivers/GitHubDriver.js";
|
|
62
|
-
export { GoogleDriver } from "./firstcontact/drivers/GoogleDriver.js";
|
|
63
|
-
export { FirstContactManager } from "./firstcontact/FirstContactManager.js";
|
|
64
|
-
export type {
|
|
65
|
-
FirstContactDriver,
|
|
66
|
-
OAuthConfig,
|
|
67
|
-
OAuthToken,
|
|
68
|
-
OAuthUser,
|
|
69
|
-
} from "./firstcontact/types.js";
|
|
70
64
|
export {
|
|
71
65
|
Guard,
|
|
72
66
|
getGuardMetadata,
|
|
@@ -178,9 +172,13 @@ export {
|
|
|
178
172
|
export type { JwtClaims, JwtStrategyConfig } from "./strategies/JwtStrategy.js";
|
|
179
173
|
export { generateJwtSecret, JwtStrategy } from "./strategies/JwtStrategy.js";
|
|
180
174
|
export type {
|
|
175
|
+
SessionGuardState,
|
|
181
176
|
SessionStore,
|
|
182
177
|
SessionStrategyConfig,
|
|
183
178
|
} from "./strategies/SessionStrategy.js";
|
|
184
|
-
export {
|
|
179
|
+
export {
|
|
180
|
+
createSessionGuardState,
|
|
181
|
+
SessionStrategy,
|
|
182
|
+
} from "./strategies/SessionStrategy.js";
|
|
185
183
|
export type { BlacklistDriver } from "./TokenBlacklist.js";
|
|
186
184
|
export { MemoryBlacklistDriver, TokenBlacklist } from "./TokenBlacklist.js";
|
package/src/middleware.ts
CHANGED
|
@@ -101,6 +101,8 @@ export interface WardenContext {
|
|
|
101
101
|
request: {
|
|
102
102
|
/** Ream's `HttpContext` exposes headers as a METHOD, not a property. */
|
|
103
103
|
headers(): Record<string, string>;
|
|
104
|
+
/** Read the encrypted remember-me cookie back. Optional, like its writer. */
|
|
105
|
+
encryptedCookie?: (name: string) => string | null;
|
|
104
106
|
};
|
|
105
107
|
/**
|
|
106
108
|
* Per-request IoC resolver (Ream's `ctx.containerResolver`). Warden resolves
|
|
@@ -111,6 +113,21 @@ export interface WardenContext {
|
|
|
111
113
|
response: {
|
|
112
114
|
status: (code: number) => unknown;
|
|
113
115
|
json: (data: unknown) => void;
|
|
116
|
+
/**
|
|
117
|
+
* Write an ENCRYPTED cookie, for the remember-me token. Optional: a
|
|
118
|
+
* host without it simply cannot offer "keep me signed in", and
|
|
119
|
+
* `login(user, true)` says so rather than pretending.
|
|
120
|
+
*
|
|
121
|
+
* Encrypted and not merely signed, because the value IS the credential
|
|
122
|
+
* — anyone who reads it can present it.
|
|
123
|
+
*/
|
|
124
|
+
encryptedCookie?: (
|
|
125
|
+
name: string,
|
|
126
|
+
value: string,
|
|
127
|
+
options?: Record<string, unknown>,
|
|
128
|
+
) => unknown;
|
|
129
|
+
/** Drop a cookie (used to clear the remember-me one). */
|
|
130
|
+
clearCookie?: (name: string, options?: Record<string, unknown>) => unknown;
|
|
114
131
|
/**
|
|
115
132
|
* Redirect the response (Ream's `ctx.response.redirect`). Optional so a
|
|
116
133
|
* minimal host without it still gets the 401 JSON fallback — Warden does
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// GENERATED FROM THE RUST — do not edit.
|
|
2
|
+
//
|
|
3
|
+
// Produced by scripts/generate-napi-types.mjs from napi-derive's type-def
|
|
4
|
+
// output. Editing this file by hand puts it back where it started: a
|
|
5
|
+
// description that can disagree with the code it describes.
|
|
6
|
+
|
|
7
|
+
export declare function jwtSign(payload: string, secret: string): string;
|
|
8
|
+
|
|
9
|
+
export declare function jwtVerify(token: string, secret: string): string;
|
|
10
|
+
|
|
11
|
+
export declare function constantTimeEq(a: string, b: string): boolean;
|
|
12
|
+
|
|
13
|
+
export declare function hmacSign(data: string, secret: string): string;
|
|
14
|
+
|
|
15
|
+
export declare function hmacVerify(
|
|
16
|
+
data: string,
|
|
17
|
+
signature: string,
|
|
18
|
+
secret: string,
|
|
19
|
+
): boolean;
|
|
20
|
+
|
|
21
|
+
export declare function randomBytes(len: number): string;
|
|
22
|
+
|
|
23
|
+
export declare function randomHex(len: number): string;
|
package/src/native.ts
CHANGED
|
@@ -21,15 +21,14 @@ const platformMap: Record<string, string> = {
|
|
|
21
21
|
"win32-x64": "win32-x64-msvc",
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
24
|
+
/**
|
|
25
|
+
* The engine's surface, as the Rust declares it.
|
|
26
|
+
*
|
|
27
|
+
* Derived from `./native/generated.js` — written by `pnpm build:napi-types`
|
|
28
|
+
* from napi-derive's own `type-def` output — rather than restated here, where
|
|
29
|
+
* nothing would notice a `pub fn` gaining a parameter or changing its return.
|
|
30
|
+
*/
|
|
31
|
+
export type NativeWarden = typeof import("./native/generated.js");
|
|
33
32
|
|
|
34
33
|
let native: NativeWarden | undefined;
|
|
35
34
|
|
|
@@ -65,13 +65,41 @@ export interface SessionStrategyConfig {
|
|
|
65
65
|
/** Two years, Adonis' `rememberMeTokensAge` default. */
|
|
66
66
|
const DEFAULT_REMEMBER_AGE_SECONDS = 63_072_000;
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* The flags a session guard reports about THE CURRENT REQUEST — whether the
|
|
70
|
+
* user was revived from a remember-me cookie, whether one was even tried, and
|
|
71
|
+
* whether `logout()` has run.
|
|
72
|
+
*
|
|
73
|
+
* They live here, in a per-request object, and NOT on the strategy: a strategy
|
|
74
|
+
* is built once from config and shared by every request the app serves, so a
|
|
75
|
+
* flag stored on it would answer the next request with the previous one's
|
|
76
|
+
* truth — a session restored from a cookie would keep looking like one long
|
|
77
|
+
* after, and a logout would make every later request read as logged out.
|
|
78
|
+
* Upstream avoids this by building a fresh guard per request; the strategy is
|
|
79
|
+
* shared here, so the state is what moves.
|
|
80
|
+
*/
|
|
81
|
+
export interface SessionGuardState {
|
|
82
|
+
/** The user was revived from a remember-me cookie rather than signing in. */
|
|
83
|
+
viaRemember: boolean;
|
|
84
|
+
/** A remember-me cookie was tried at all — whether or not it worked. */
|
|
85
|
+
attemptedViaRemember: boolean;
|
|
86
|
+
/** `logout()` has run during this request. */
|
|
87
|
+
isLoggedOut: boolean;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** A fresh set of per-request flags, all false. */
|
|
91
|
+
export function createSessionGuardState(): SessionGuardState {
|
|
92
|
+
return {
|
|
93
|
+
viaRemember: false,
|
|
94
|
+
attemptedViaRemember: false,
|
|
95
|
+
isLoggedOut: false,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
68
99
|
export class SessionStrategy implements AuthStrategy {
|
|
69
100
|
name = "session";
|
|
70
101
|
#config: SessionStrategyConfig;
|
|
71
102
|
#sessionKey: string;
|
|
72
|
-
#viaRemember = false;
|
|
73
|
-
#loggedOut = false;
|
|
74
|
-
#attemptedViaRemember = false;
|
|
75
103
|
|
|
76
104
|
constructor(config: SessionStrategyConfig) {
|
|
77
105
|
this.#config = config;
|
|
@@ -88,37 +116,6 @@ export class SessionStrategy implements AuthStrategy {
|
|
|
88
116
|
return this.#config.rememberMeTokens !== undefined;
|
|
89
117
|
}
|
|
90
118
|
|
|
91
|
-
/**
|
|
92
|
-
* Whether the current user was revived from a remember-me cookie rather
|
|
93
|
-
* than signing in (AdonisJS `viaRemember`).
|
|
94
|
-
*
|
|
95
|
-
* This is the distinction that lets an app demand the password again before
|
|
96
|
-
* something sensitive — changing an email, spending money, deleting an
|
|
97
|
-
* account. Nothing reported it, so a session restored from a cookie looked
|
|
98
|
-
* exactly like one where the user had just typed their password.
|
|
99
|
-
*/
|
|
100
|
-
get viaRemember(): boolean {
|
|
101
|
-
return this.#viaRemember;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Whether a remember-me token was even tried on this request (AdonisJS
|
|
106
|
-
* `attemptedViaRemember`) — true whether or not it worked.
|
|
107
|
-
*/
|
|
108
|
-
get attemptedViaRemember(): boolean {
|
|
109
|
-
return this.#attemptedViaRemember;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Whether `logout()` ran on this guard (AdonisJS `isLoggedOut`).
|
|
114
|
-
*
|
|
115
|
-
* A handler that logs out and then keeps working — clearing a cart, writing
|
|
116
|
-
* an audit line — could not tell that the session was already gone.
|
|
117
|
-
*/
|
|
118
|
-
get isLoggedOut(): boolean {
|
|
119
|
-
return this.#loggedOut;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
119
|
/** The session key the user id is stored under (AdonisJS `sessionKeyName`). */
|
|
123
120
|
get sessionKeyName(): string {
|
|
124
121
|
return this.#sessionKey;
|
|
@@ -130,6 +127,11 @@ export class SessionStrategy implements AuthStrategy {
|
|
|
130
127
|
}
|
|
131
128
|
|
|
132
129
|
#rememberMeAge(): number {
|
|
130
|
+
return this.rememberMeAgeSeconds;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** How long a remember-me token lives, in SECONDS (the cookie's max-age). */
|
|
134
|
+
get rememberMeAgeSeconds(): number {
|
|
133
135
|
return this.#config.rememberMeAge ?? DEFAULT_REMEMBER_AGE_SECONDS;
|
|
134
136
|
}
|
|
135
137
|
|
|
@@ -155,10 +157,11 @@ export class SessionStrategy implements AuthStrategy {
|
|
|
155
157
|
*/
|
|
156
158
|
async authenticateViaRememberMeToken(
|
|
157
159
|
cookieValue: unknown,
|
|
160
|
+
state?: SessionGuardState,
|
|
158
161
|
): Promise<{ user: UserPayload; cookieValue: string } | null> {
|
|
159
162
|
const driver = this.#config.rememberMeTokens;
|
|
160
163
|
if (!driver) return null;
|
|
161
|
-
|
|
164
|
+
if (state) state.attemptedViaRemember = true;
|
|
162
165
|
|
|
163
166
|
const recycled = await verifyAndRecycleRememberMeToken(
|
|
164
167
|
driver,
|
|
@@ -170,7 +173,7 @@ export class SessionStrategy implements AuthStrategy {
|
|
|
170
173
|
const user = await this.#config.findUser(recycled.userId);
|
|
171
174
|
if (!user) return null;
|
|
172
175
|
|
|
173
|
-
|
|
176
|
+
if (state) state.viaRemember = true;
|
|
174
177
|
return { user, cookieValue: recycled.value };
|
|
175
178
|
}
|
|
176
179
|
|
|
@@ -240,14 +243,33 @@ export class SessionStrategy implements AuthStrategy {
|
|
|
240
243
|
* migration is handled by Ream's `SessionMiddleware` on the response
|
|
241
244
|
* path — see `wasRegenerated()` there.
|
|
242
245
|
*/
|
|
243
|
-
|
|
246
|
+
/**
|
|
247
|
+
* Seat a user in the session, without deciding HOW they got there.
|
|
248
|
+
*
|
|
249
|
+
* Split out from {@link login} because the remember-me path needs the seat
|
|
250
|
+
* but not the flags: `login()` means a password was typed, and resetting
|
|
251
|
+
* `viaRemember` there would erase the very fact a cookie-revived session
|
|
252
|
+
* exists to report.
|
|
253
|
+
*/
|
|
254
|
+
seatSession(user: UserPayload, session: SessionStore): void {
|
|
244
255
|
session.regenerate();
|
|
245
256
|
session.put(this.#sessionKey, user.id);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async login(
|
|
260
|
+
user: UserPayload,
|
|
261
|
+
session: SessionStore,
|
|
262
|
+
state?: SessionGuardState,
|
|
263
|
+
): Promise<void> {
|
|
264
|
+
this.seatSession(user, session);
|
|
265
|
+
if (state) {
|
|
266
|
+
state.isLoggedOut = false;
|
|
267
|
+
// A password was typed: this session is no longer "via remember",
|
|
268
|
+
// even if a cookie was tried earlier in the same request. Without
|
|
269
|
+
// the reset the flag would stay true and a re-auth prompt would
|
|
270
|
+
// never fire.
|
|
271
|
+
state.viaRemember = false;
|
|
272
|
+
}
|
|
251
273
|
}
|
|
252
274
|
|
|
253
275
|
/**
|
|
@@ -267,10 +289,15 @@ export class SessionStrategy implements AuthStrategy {
|
|
|
267
289
|
* The remember-me token is revoked separately through
|
|
268
290
|
* {@link revokeRememberMeToken}, because only the caller holds the cookie.
|
|
269
291
|
*/
|
|
270
|
-
async logout(
|
|
292
|
+
async logout(
|
|
293
|
+
session: SessionStore,
|
|
294
|
+
state?: SessionGuardState,
|
|
295
|
+
): Promise<void> {
|
|
271
296
|
session.forget(this.#sessionKey);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
297
|
+
if (state) {
|
|
298
|
+
state.viaRemember = false;
|
|
299
|
+
state.attemptedViaRemember = false;
|
|
300
|
+
state.isLoggedOut = true;
|
|
301
|
+
}
|
|
275
302
|
}
|
|
276
303
|
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FirstContactManager — OAuth2 social authentication.
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* firstContact.use('google').redirectUrl()
|
|
6
|
-
* firstContact.use('google').callback(code)
|
|
7
|
-
*/
|
|
8
|
-
import type { FirstContactDriver, OAuthToken, OAuthUser } from "./types.js";
|
|
9
|
-
export declare class FirstContactManager {
|
|
10
|
-
#private;
|
|
11
|
-
use(name: string): FirstContactDriver;
|
|
12
|
-
register(name: string, driver: FirstContactDriver): void;
|
|
13
|
-
redirect(name: string, state?: string): string;
|
|
14
|
-
/**
|
|
15
|
-
* Handle the OAuth callback. Pass `state` (from the query string) and
|
|
16
|
-
* `expectedState` (from the session, stored at redirect time) for CSRF
|
|
17
|
-
* protection. Omitting `expectedState` logs a security warning.
|
|
18
|
-
*/
|
|
19
|
-
callback(name: string, code: string, state?: string, expectedState?: string): Promise<{
|
|
20
|
-
user: OAuthUser;
|
|
21
|
-
token: OAuthToken;
|
|
22
|
-
}>;
|
|
23
|
-
get registeredDrivers(): string[];
|
|
24
|
-
}
|
|
25
|
-
//# sourceMappingURL=FirstContactManager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FirstContactManager.d.ts","sourceRoot":"","sources":["../../src/firstcontact/FirstContactManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5E,qBAAa,mBAAmB;;IAG/B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB;IASrC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAIxD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAI9C;;;;OAIG;IACG,QAAQ,CACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;IAUlD,IAAI,iBAAiB,IAAI,MAAM,EAAE,CAEhC;CACD"}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FirstContactManager — OAuth2 social authentication.
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* firstContact.use('google').redirectUrl()
|
|
6
|
-
* firstContact.use('google').callback(code)
|
|
7
|
-
*/
|
|
8
|
-
export class FirstContactManager {
|
|
9
|
-
#drivers = new Map();
|
|
10
|
-
use(name) {
|
|
11
|
-
const driver = this.#drivers.get(name);
|
|
12
|
-
if (!driver)
|
|
13
|
-
throw new Error(`OAuth driver '${name}' not registered. Available: ${[...this.#drivers.keys()].join(", ")}`);
|
|
14
|
-
return driver;
|
|
15
|
-
}
|
|
16
|
-
register(name, driver) {
|
|
17
|
-
this.#drivers.set(name, driver);
|
|
18
|
-
}
|
|
19
|
-
redirect(name, state) {
|
|
20
|
-
return this.use(name).redirectUrl(state);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Handle the OAuth callback. Pass `state` (from the query string) and
|
|
24
|
-
* `expectedState` (from the session, stored at redirect time) for CSRF
|
|
25
|
-
* protection. Omitting `expectedState` logs a security warning.
|
|
26
|
-
*/
|
|
27
|
-
async callback(name, code, state, expectedState) {
|
|
28
|
-
if (!expectedState) {
|
|
29
|
-
throw new Error(`[warden] OAuth callback for '${name}' requires expectedState for CSRF protection. ` +
|
|
30
|
-
`Store the state from redirect() in the session and pass it here.`);
|
|
31
|
-
}
|
|
32
|
-
return this.use(name).callback(code, state, expectedState);
|
|
33
|
-
}
|
|
34
|
-
get registeredDrivers() {
|
|
35
|
-
return [...this.#drivers.keys()];
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=FirstContactManager.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FirstContactManager.js","sourceRoot":"","sources":["../../src/firstcontact/FirstContactManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,OAAO,mBAAmB;IAC/B,QAAQ,GAAoC,IAAI,GAAG,EAAE,CAAC;IAEtD,GAAG,CAAC,IAAY;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM;YACV,MAAM,IAAI,KAAK,CACd,iBAAiB,IAAI,gCAAgC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC3F,CAAC;QACH,OAAO,MAAM,CAAC;IACf,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,MAA0B;QAChD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,KAAc;QACpC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAQ,CACb,IAAY,EACZ,IAAY,EACZ,KAAc,EACd,aAAsB;QAEtB,IAAI,CAAC,aAAa,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CACd,gCAAgC,IAAI,gDAAgD;gBACnF,kEAAkE,CACnE,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,iBAAiB;QACpB,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAClC,CAAC;CACD"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub OAuth2 driver for FirstContact.
|
|
3
|
-
*/
|
|
4
|
-
import type { FirstContactDriver, OAuthConfig, OAuthToken, OAuthUser } from "../types.js";
|
|
5
|
-
export declare class GitHubDriver implements FirstContactDriver {
|
|
6
|
-
private config;
|
|
7
|
-
constructor(config: OAuthConfig);
|
|
8
|
-
redirectUrl(state?: string): string;
|
|
9
|
-
callback(code: string, state?: string, expectedState?: string): Promise<{
|
|
10
|
-
user: OAuthUser;
|
|
11
|
-
token: OAuthToken;
|
|
12
|
-
}>;
|
|
13
|
-
}
|
|
14
|
-
//# sourceMappingURL=GitHubDriver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GitHubDriver.d.ts","sourceRoot":"","sources":["../../../src/firstcontact/drivers/GitHubDriver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,SAAS,EACT,MAAM,aAAa,CAAC;AAGrB,qBAAa,YAAa,YAAW,kBAAkB;IAC1C,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,WAAW;IAEvC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAU7B,QAAQ,CACb,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;CA+ClD"}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GitHub OAuth2 driver for FirstContact.
|
|
3
|
-
*/
|
|
4
|
-
import { assertOAuthState } from "../types.js";
|
|
5
|
-
export class GitHubDriver {
|
|
6
|
-
config;
|
|
7
|
-
constructor(config) {
|
|
8
|
-
this.config = config;
|
|
9
|
-
}
|
|
10
|
-
redirectUrl(state) {
|
|
11
|
-
const params = new URLSearchParams({
|
|
12
|
-
client_id: this.config.clientId,
|
|
13
|
-
redirect_uri: this.config.callbackUrl,
|
|
14
|
-
scope: (this.config.scopes ?? ["read:user", "user:email"]).join(" "),
|
|
15
|
-
...(state ? { state } : {}),
|
|
16
|
-
});
|
|
17
|
-
return `https://github.com/login/oauth/authorize?${params}`;
|
|
18
|
-
}
|
|
19
|
-
async callback(code, state, expectedState) {
|
|
20
|
-
assertOAuthState(state, expectedState);
|
|
21
|
-
const tokenRes = await fetch("https://github.com/login/oauth/access_token", {
|
|
22
|
-
method: "POST",
|
|
23
|
-
headers: {
|
|
24
|
-
Accept: "application/json",
|
|
25
|
-
"Content-Type": "application/json",
|
|
26
|
-
},
|
|
27
|
-
body: JSON.stringify({
|
|
28
|
-
client_id: this.config.clientId,
|
|
29
|
-
client_secret: this.config.clientSecret,
|
|
30
|
-
code,
|
|
31
|
-
}),
|
|
32
|
-
});
|
|
33
|
-
if (!tokenRes.ok) {
|
|
34
|
-
throw new Error(`GitHub OAuth token exchange failed (HTTP ${tokenRes.status})`);
|
|
35
|
-
}
|
|
36
|
-
const tokens = (await tokenRes.json());
|
|
37
|
-
if (!tokens.access_token)
|
|
38
|
-
throw new Error("GitHub OAuth: no access_token in response");
|
|
39
|
-
const userRes = await fetch("https://api.github.com/user", {
|
|
40
|
-
headers: {
|
|
41
|
-
Authorization: `Bearer ${tokens.access_token}`,
|
|
42
|
-
Accept: "application/json",
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
if (!userRes.ok)
|
|
46
|
-
throw new Error(`GitHub user API failed (${userRes.status})`);
|
|
47
|
-
const raw = (await userRes.json());
|
|
48
|
-
return {
|
|
49
|
-
user: {
|
|
50
|
-
id: String(raw.id ?? ""),
|
|
51
|
-
email: String(raw.email ?? ""),
|
|
52
|
-
name: String(raw.name ?? raw.login ?? ""),
|
|
53
|
-
avatarUrl: raw.avatar_url,
|
|
54
|
-
raw,
|
|
55
|
-
},
|
|
56
|
-
token: { accessToken: String(tokens.access_token) },
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
//# sourceMappingURL=GitHubDriver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GitHubDriver.js","sourceRoot":"","sources":["../../../src/firstcontact/drivers/GitHubDriver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,OAAO,YAAY;IACJ;IAApB,YAAoB,MAAmB;QAAnB,WAAM,GAAN,MAAM,CAAa;IAAG,CAAC;IAE3C,WAAW,CAAC,KAAc;QACzB,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YAClC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACrC,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YACpE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3B,CAAC,CAAC;QACH,OAAO,4CAA4C,MAAM,EAAE,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,QAAQ,CACb,IAAY,EACZ,KAAc,EACd,aAAsB;QAEtB,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC3B,6CAA6C,EAC7C;YACC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACR,MAAM,EAAE,kBAAkB;gBAC1B,cAAc,EAAE,kBAAkB;aAClC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACpB,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAC/B,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;gBACvC,IAAI;aACJ,CAAC;SACF,CACD,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACd,4CAA4C,QAAQ,CAAC,MAAM,GAAG,CAC9D,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,YAAY;YACvB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAE9D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,6BAA6B,EAAE;YAC1D,OAAO,EAAE;gBACR,aAAa,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE;gBAC9C,MAAM,EAAE,kBAAkB;aAC1B;SACD,CAAC,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,EAAE;YACd,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAA4B,CAAC;QAE9D,OAAO;YACN,IAAI,EAAE;gBACL,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;gBACxB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC9B,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;gBACzC,SAAS,EAAE,GAAG,CAAC,UAAgC;gBAC/C,GAAG;aACH;YACD,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE;SACnD,CAAC;IACH,CAAC;CACD"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google OAuth2 driver for FirstContact.
|
|
3
|
-
*/
|
|
4
|
-
import type { FirstContactDriver, OAuthConfig, OAuthToken, OAuthUser } from "../types.js";
|
|
5
|
-
export declare class GoogleDriver implements FirstContactDriver {
|
|
6
|
-
private config;
|
|
7
|
-
constructor(config: OAuthConfig);
|
|
8
|
-
redirectUrl(state?: string): string;
|
|
9
|
-
callback(code: string, state?: string, expectedState?: string): Promise<{
|
|
10
|
-
user: OAuthUser;
|
|
11
|
-
token: OAuthToken;
|
|
12
|
-
}>;
|
|
13
|
-
}
|
|
14
|
-
//# sourceMappingURL=GoogleDriver.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleDriver.d.ts","sourceRoot":"","sources":["../../../src/firstcontact/drivers/GoogleDriver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EACX,kBAAkB,EAClB,WAAW,EACX,UAAU,EACV,SAAS,EACT,MAAM,aAAa,CAAC;AAGrB,qBAAa,YAAa,YAAW,kBAAkB;IAC1C,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,WAAW;IAEvC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAY7B,QAAQ,CACb,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC;CAgDlD"}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Google OAuth2 driver for FirstContact.
|
|
3
|
-
*/
|
|
4
|
-
import { assertOAuthState } from "../types.js";
|
|
5
|
-
export class GoogleDriver {
|
|
6
|
-
config;
|
|
7
|
-
constructor(config) {
|
|
8
|
-
this.config = config;
|
|
9
|
-
}
|
|
10
|
-
redirectUrl(state) {
|
|
11
|
-
const params = new URLSearchParams({
|
|
12
|
-
client_id: this.config.clientId,
|
|
13
|
-
redirect_uri: this.config.callbackUrl,
|
|
14
|
-
response_type: "code",
|
|
15
|
-
scope: (this.config.scopes ?? ["openid", "email", "profile"]).join(" "),
|
|
16
|
-
access_type: "offline",
|
|
17
|
-
...(state ? { state } : {}),
|
|
18
|
-
});
|
|
19
|
-
return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;
|
|
20
|
-
}
|
|
21
|
-
async callback(code, state, expectedState) {
|
|
22
|
-
// CSRF protection: validate state matches what we sent in redirectUrl().
|
|
23
|
-
assertOAuthState(state, expectedState);
|
|
24
|
-
const tokenRes = await fetch("https://oauth2.googleapis.com/token", {
|
|
25
|
-
method: "POST",
|
|
26
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
27
|
-
body: new URLSearchParams({
|
|
28
|
-
code,
|
|
29
|
-
client_id: this.config.clientId,
|
|
30
|
-
client_secret: this.config.clientSecret,
|
|
31
|
-
redirect_uri: this.config.callbackUrl,
|
|
32
|
-
grant_type: "authorization_code",
|
|
33
|
-
}),
|
|
34
|
-
});
|
|
35
|
-
if (!tokenRes.ok) {
|
|
36
|
-
throw new Error(`Google OAuth token exchange failed (HTTP ${tokenRes.status})`);
|
|
37
|
-
}
|
|
38
|
-
const tokens = (await tokenRes.json());
|
|
39
|
-
if (!tokens.access_token)
|
|
40
|
-
throw new Error("Google OAuth: no access_token in response");
|
|
41
|
-
const userRes = await fetch("https://www.googleapis.com/oauth2/v2/userinfo", {
|
|
42
|
-
headers: { Authorization: `Bearer ${tokens.access_token}` },
|
|
43
|
-
});
|
|
44
|
-
if (!userRes.ok)
|
|
45
|
-
throw new Error(`Google userinfo failed (${userRes.status})`);
|
|
46
|
-
const raw = (await userRes.json());
|
|
47
|
-
return {
|
|
48
|
-
user: {
|
|
49
|
-
id: String(raw.id ?? ""),
|
|
50
|
-
email: String(raw.email ?? ""),
|
|
51
|
-
name: String(raw.name ?? ""),
|
|
52
|
-
avatarUrl: raw.picture,
|
|
53
|
-
raw,
|
|
54
|
-
},
|
|
55
|
-
token: {
|
|
56
|
-
accessToken: String(tokens.access_token),
|
|
57
|
-
refreshToken: tokens.refresh_token,
|
|
58
|
-
expiresIn: tokens.expires_in,
|
|
59
|
-
},
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
//# sourceMappingURL=GoogleDriver.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleDriver.js","sourceRoot":"","sources":["../../../src/firstcontact/drivers/GoogleDriver.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,OAAO,YAAY;IACJ;IAApB,YAAoB,MAAmB;QAAnB,WAAM,GAAN,MAAM,CAAa;IAAG,CAAC;IAE3C,WAAW,CAAC,KAAc;QACzB,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YAClC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACrC,aAAa,EAAE,MAAM;YACrB,KAAK,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YACvE,WAAW,EAAE,SAAS;YACtB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3B,CAAC,CAAC;QACH,OAAO,gDAAgD,MAAM,EAAE,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,QAAQ,CACb,IAAY,EACZ,KAAc,EACd,aAAsB;QAEtB,yEAAyE;QACzE,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,qCAAqC,EAAE;YACnE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;YAChE,IAAI,EAAE,IAAI,eAAe,CAAC;gBACzB,IAAI;gBACJ,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;gBAC/B,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY;gBACvC,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;gBACrC,UAAU,EAAE,oBAAoB;aAChC,CAAC;SACF,CAAC,CAAC;QACH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CACd,4CAA4C,QAAQ,CAAC,MAAM,GAAG,CAC9D,CAAC;QACH,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA4B,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,YAAY;YACvB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAE9D,MAAM,OAAO,GAAG,MAAM,KAAK,CAC1B,+CAA+C,EAC/C;YACC,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE,EAAE;SAC3D,CACD,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,EAAE;YACd,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC/D,MAAM,GAAG,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAA4B,CAAC;QAE9D,OAAO;YACN,IAAI,EAAE;gBACL,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;gBACxB,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC9B,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC5B,SAAS,EAAE,GAAG,CAAC,OAA6B;gBAC5C,GAAG;aACH;YACD,KAAK,EAAE;gBACN,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC;gBACxC,YAAY,EAAE,MAAM,CAAC,aAAmC;gBACxD,SAAS,EAAE,MAAM,CAAC,UAAgC;aAClD;SACD,CAAC;IACH,CAAC;CACD"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FirstContact — OAuth2 social authentication types.
|
|
3
|
-
*/
|
|
4
|
-
export interface OAuthConfig {
|
|
5
|
-
clientId: string;
|
|
6
|
-
clientSecret: string;
|
|
7
|
-
callbackUrl: string;
|
|
8
|
-
scopes?: string[];
|
|
9
|
-
}
|
|
10
|
-
export interface OAuthUser {
|
|
11
|
-
id: string;
|
|
12
|
-
email: string;
|
|
13
|
-
name: string;
|
|
14
|
-
avatarUrl?: string;
|
|
15
|
-
raw: Record<string, unknown>;
|
|
16
|
-
}
|
|
17
|
-
export interface OAuthToken {
|
|
18
|
-
accessToken: string;
|
|
19
|
-
refreshToken?: string;
|
|
20
|
-
expiresIn?: number;
|
|
21
|
-
}
|
|
22
|
-
export interface FirstContactDriver {
|
|
23
|
-
redirectUrl(state?: string): string;
|
|
24
|
-
/**
|
|
25
|
-
* Handle the OAuth callback. `state` MUST be validated against the value
|
|
26
|
-
* originally passed to `redirectUrl()` to prevent CSRF login attacks.
|
|
27
|
-
* Throws if state is missing or mismatched.
|
|
28
|
-
*/
|
|
29
|
-
callback(code: string, state?: string, expectedState?: string): Promise<{
|
|
30
|
-
user: OAuthUser;
|
|
31
|
-
token: OAuthToken;
|
|
32
|
-
}>;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Check the OAuth `state` round-trip, failing CLOSED.
|
|
36
|
-
*
|
|
37
|
-
* The check used to be `if (expectedState && state !== expectedState)`, so a
|
|
38
|
-
* caller that passed no expected state got NO CSRF protection and no sign that
|
|
39
|
-
* it was missing. A driver used directly — without the manager, which already
|
|
40
|
-
* refuses — was therefore open by default. Anything that cannot be verified is
|
|
41
|
-
* refused instead.
|
|
42
|
-
*/
|
|
43
|
-
export declare function assertOAuthState(state: string | undefined, expectedState: string | undefined): void;
|
|
44
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/firstcontact/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,UAAU;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IAClC,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CACP,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;QAAE,IAAI,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;CACnD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC/B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,aAAa,EAAE,MAAM,GAAG,SAAS,GAC/B,IAAI,CAUN"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FirstContact — OAuth2 social authentication types.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Check the OAuth `state` round-trip, failing CLOSED.
|
|
6
|
-
*
|
|
7
|
-
* The check used to be `if (expectedState && state !== expectedState)`, so a
|
|
8
|
-
* caller that passed no expected state got NO CSRF protection and no sign that
|
|
9
|
-
* it was missing. A driver used directly — without the manager, which already
|
|
10
|
-
* refuses — was therefore open by default. Anything that cannot be verified is
|
|
11
|
-
* refused instead.
|
|
12
|
-
*/
|
|
13
|
-
export function assertOAuthState(state, expectedState) {
|
|
14
|
-
if (!expectedState) {
|
|
15
|
-
throw new Error("[warden] OAuth callback requires expectedState for CSRF protection. " +
|
|
16
|
-
"Store the state given to redirectUrl() in the session and pass it here.");
|
|
17
|
-
}
|
|
18
|
-
if (state !== expectedState) {
|
|
19
|
-
throw new Error("OAuth state mismatch — possible CSRF attack");
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/firstcontact/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAqCH;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAyB,EACzB,aAAiC;IAEjC,IAAI,CAAC,aAAa,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACd,sEAAsE;YACrE,yEAAyE,CAC1E,CAAC;IACH,CAAC;IACD,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IAChE,CAAC;AACF,CAAC"}
|