auth-vir 1.3.2 → 2.0.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/README.md +27 -18
- package/dist/auth-client/backend-auth.client.d.ts +177 -0
- package/dist/auth-client/backend-auth.client.js +232 -0
- package/dist/auth-client/frontend-auth.client.d.ts +64 -0
- package/dist/auth-client/frontend-auth.client.js +107 -0
- package/dist/auth.d.ts +32 -46
- package/dist/auth.js +36 -36
- package/dist/cookie.d.ts +15 -4
- package/dist/cookie.js +16 -4
- package/dist/csrf-token.d.ts +113 -3
- package/dist/csrf-token.js +101 -5
- package/dist/generated/browser.d.ts +9 -0
- package/dist/generated/browser.js +16 -0
- package/dist/generated/client.d.ts +26 -0
- package/dist/generated/client.js +31 -0
- package/dist/generated/commonInputTypes.d.ts +122 -0
- package/dist/generated/commonInputTypes.js +1 -0
- package/dist/generated/enums.d.ts +1 -0
- package/dist/generated/enums.js +9 -0
- package/dist/generated/internal/class.d.ts +126 -0
- package/dist/generated/internal/class.js +84 -0
- package/dist/generated/internal/prismaNamespace.d.ts +544 -0
- package/dist/generated/internal/prismaNamespace.js +101 -0
- package/dist/generated/internal/prismaNamespaceBrowser.d.ts +75 -0
- package/dist/generated/internal/prismaNamespaceBrowser.js +69 -0
- package/dist/generated/models/User.d.ts +983 -0
- package/dist/generated/models/User.js +1 -0
- package/dist/generated/models.d.ts +2 -0
- package/dist/generated/models.js +1 -0
- package/dist/generated/shapes.gen.d.ts +8 -0
- package/dist/generated/shapes.gen.js +11 -0
- package/dist/headers.d.ts +20 -0
- package/dist/headers.js +33 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/jwt/jwt.d.ts +11 -2
- package/dist/jwt/jwt.js +14 -3
- package/dist/jwt/user-jwt.d.ts +8 -8
- package/dist/jwt/user-jwt.js +12 -9
- package/package.json +12 -7
- package/src/auth-client/backend-auth.client.ts +500 -0
- package/src/auth-client/frontend-auth.client.ts +182 -0
- package/src/auth.ts +99 -77
- package/src/cookie.ts +20 -8
- package/src/csrf-token.ts +196 -5
- package/src/generated/browser.ts +23 -0
- package/src/generated/client.ts +47 -0
- package/src/generated/commonInputTypes.ts +147 -0
- package/src/generated/enums.ts +14 -0
- package/src/generated/internal/class.ts +236 -0
- package/src/generated/internal/prismaNamespace.ts +761 -0
- package/src/generated/internal/prismaNamespaceBrowser.ts +102 -0
- package/src/generated/models/User.ts +1135 -0
- package/src/generated/models.ts +11 -0
- package/src/generated/shapes.gen.ts +15 -0
- package/src/headers.ts +35 -0
- package/src/index.ts +2 -0
- package/src/jwt/jwt.ts +34 -5
- package/src/jwt/user-jwt.ts +21 -12
package/src/auth.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
import {type PartialWithUndefined} from '@augment-vir/common';
|
|
2
|
+
import {type FullDate, type UtcTimezone} from 'date-vir';
|
|
1
3
|
import {
|
|
4
|
+
AuthCookieName,
|
|
2
5
|
clearAuthCookie,
|
|
3
6
|
type CookieParams,
|
|
4
7
|
extractCookieJwt,
|
|
5
8
|
generateAuthCookie,
|
|
6
9
|
} from './cookie.js';
|
|
7
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
extractCsrfTokenHeader,
|
|
12
|
+
generateCsrfToken,
|
|
13
|
+
parseCsrfToken,
|
|
14
|
+
storeCsrfToken,
|
|
15
|
+
wipeCurrentCsrfToken,
|
|
16
|
+
} from './csrf-token.js';
|
|
17
|
+
import {AuthHeaderName} from './headers.js';
|
|
8
18
|
import {type ParseJwtParams} from './jwt/jwt.js';
|
|
9
19
|
|
|
10
20
|
/**
|
|
@@ -30,6 +40,32 @@ function readHeader(headers: HeaderContainer, headerName: string): string | unde
|
|
|
30
40
|
}
|
|
31
41
|
}
|
|
32
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Output from {@link extractUserIdFromRequestHeaders}.
|
|
45
|
+
*
|
|
46
|
+
* @category Internal
|
|
47
|
+
*/
|
|
48
|
+
export type UserIdResult<UserId extends string | number> = {
|
|
49
|
+
userId: UserId;
|
|
50
|
+
jwtExpiration: FullDate<UtcTimezone>;
|
|
51
|
+
cookieName: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function readCsrfTokenHeader(
|
|
55
|
+
headers: HeaderContainer,
|
|
56
|
+
overrides: PartialWithUndefined<{
|
|
57
|
+
csrfHeaderName: string;
|
|
58
|
+
}>,
|
|
59
|
+
): string | undefined {
|
|
60
|
+
const rawCsrfToken = readHeader(headers, overrides.csrfHeaderName || AuthHeaderName.CsrfToken);
|
|
61
|
+
|
|
62
|
+
if (!rawCsrfToken) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return parseCsrfToken(rawCsrfToken).csrfToken?.token || rawCsrfToken;
|
|
67
|
+
}
|
|
68
|
+
|
|
33
69
|
/**
|
|
34
70
|
* Extract the user id from a request by checking both the request cookie and CSRF token. This is
|
|
35
71
|
* used by host (backend) code to help verify a request. After extracting the user id using this,
|
|
@@ -38,13 +74,16 @@ function readHeader(headers: HeaderContainer, headerName: string): string | unde
|
|
|
38
74
|
* @category Auth : Host
|
|
39
75
|
* @returns The extracted user id or `undefined` if no valid auth headers exist.
|
|
40
76
|
*/
|
|
41
|
-
export async function extractUserIdFromRequestHeaders(
|
|
77
|
+
export async function extractUserIdFromRequestHeaders<UserId extends string | number>(
|
|
42
78
|
headers: HeaderContainer,
|
|
43
79
|
jwtParams: Readonly<ParseJwtParams>,
|
|
44
|
-
cookieName
|
|
45
|
-
|
|
80
|
+
cookieName: string = AuthCookieName.Auth,
|
|
81
|
+
overrides: PartialWithUndefined<{
|
|
82
|
+
csrfHeaderName: string;
|
|
83
|
+
}> = {},
|
|
84
|
+
): Promise<Readonly<UserIdResult<UserId>> | undefined> {
|
|
46
85
|
try {
|
|
47
|
-
const csrfToken =
|
|
86
|
+
const csrfToken = readCsrfTokenHeader(headers, overrides);
|
|
48
87
|
const cookie = readHeader(headers, 'cookie');
|
|
49
88
|
|
|
50
89
|
if (!cookie || !csrfToken) {
|
|
@@ -53,11 +92,15 @@ export async function extractUserIdFromRequestHeaders(
|
|
|
53
92
|
|
|
54
93
|
const jwt = await extractCookieJwt(cookie, jwtParams, cookieName);
|
|
55
94
|
|
|
56
|
-
if (!jwt || jwt.csrfToken !== csrfToken) {
|
|
95
|
+
if (!jwt || jwt.data.csrfToken !== csrfToken) {
|
|
57
96
|
return undefined;
|
|
58
97
|
}
|
|
59
98
|
|
|
60
|
-
return
|
|
99
|
+
return {
|
|
100
|
+
userId: jwt.data.userId as UserId,
|
|
101
|
+
jwtExpiration: jwt.jwtExpiration,
|
|
102
|
+
cookieName,
|
|
103
|
+
};
|
|
61
104
|
} catch {
|
|
62
105
|
return undefined;
|
|
63
106
|
}
|
|
@@ -69,12 +112,13 @@ export async function extractUserIdFromRequestHeaders(
|
|
|
69
112
|
* circumstances where you cannot rely on client-side JavaScript to insert the CSRF token.
|
|
70
113
|
*
|
|
71
114
|
* @deprecated Prefer {@link extractUserIdFromRequestHeaders} instead: it is more secure.
|
|
115
|
+
* @category Auth : Host
|
|
72
116
|
*/
|
|
73
|
-
export async function
|
|
117
|
+
export async function insecureExtractUserIdFromCookieAlone<UserId extends string | number>(
|
|
74
118
|
headers: HeaderContainer,
|
|
75
119
|
jwtParams: Readonly<ParseJwtParams>,
|
|
76
|
-
cookieName
|
|
77
|
-
): Promise<
|
|
120
|
+
cookieName: string = AuthCookieName.Auth,
|
|
121
|
+
): Promise<Readonly<UserIdResult<UserId>> | undefined> {
|
|
78
122
|
try {
|
|
79
123
|
const cookie = readHeader(headers, 'cookie');
|
|
80
124
|
|
|
@@ -88,7 +132,11 @@ export async function extractUserIdFromCookieAlone(
|
|
|
88
132
|
return undefined;
|
|
89
133
|
}
|
|
90
134
|
|
|
91
|
-
return
|
|
135
|
+
return {
|
|
136
|
+
userId: jwt.data.userId as UserId,
|
|
137
|
+
jwtExpiration: jwt.jwtExpiration,
|
|
138
|
+
cookieName,
|
|
139
|
+
};
|
|
92
140
|
} catch {
|
|
93
141
|
return undefined;
|
|
94
142
|
}
|
|
@@ -99,23 +147,35 @@ export async function extractUserIdFromCookieAlone(
|
|
|
99
147
|
*
|
|
100
148
|
* @category Auth : Host
|
|
101
149
|
*/
|
|
102
|
-
export async function generateSuccessfulLoginHeaders
|
|
150
|
+
export async function generateSuccessfulLoginHeaders<
|
|
151
|
+
CsrfHeaderName extends string = AuthHeaderName.CsrfToken,
|
|
152
|
+
>(
|
|
103
153
|
/** The id from your database of the user you're authenticating. */
|
|
104
|
-
userId: string,
|
|
154
|
+
userId: string | number,
|
|
105
155
|
cookieConfig: Readonly<CookieParams>,
|
|
106
|
-
|
|
107
|
-
|
|
156
|
+
overrides: PartialWithUndefined<{
|
|
157
|
+
csrfHeaderName: CsrfHeaderName;
|
|
158
|
+
}> = {},
|
|
159
|
+
): Promise<
|
|
160
|
+
{
|
|
161
|
+
'set-cookie': string;
|
|
162
|
+
} & Record<CsrfHeaderName, string>
|
|
163
|
+
> {
|
|
164
|
+
const csrfToken = generateCsrfToken(cookieConfig.cookieDuration);
|
|
165
|
+
const csrfHeaderName = (overrides.csrfHeaderName || AuthHeaderName.CsrfToken) as CsrfHeaderName;
|
|
108
166
|
|
|
109
167
|
return {
|
|
110
168
|
'set-cookie': await generateAuthCookie(
|
|
111
169
|
{
|
|
112
|
-
csrfToken,
|
|
170
|
+
csrfToken: csrfToken.token,
|
|
113
171
|
userId,
|
|
114
172
|
},
|
|
115
173
|
cookieConfig,
|
|
116
174
|
),
|
|
117
|
-
[
|
|
118
|
-
}
|
|
175
|
+
[csrfHeaderName]: JSON.stringify(csrfToken),
|
|
176
|
+
} as {
|
|
177
|
+
'set-cookie': string;
|
|
178
|
+
} & Record<CsrfHeaderName, string>;
|
|
119
179
|
}
|
|
120
180
|
|
|
121
181
|
/**
|
|
@@ -124,11 +184,22 @@ export async function generateSuccessfulLoginHeaders(
|
|
|
124
184
|
*
|
|
125
185
|
* @category Auth : Host
|
|
126
186
|
*/
|
|
127
|
-
export function generateLogoutHeaders
|
|
187
|
+
export function generateLogoutHeaders<CsrfHeaderName extends string = AuthHeaderName.CsrfToken>(
|
|
188
|
+
cookieConfig: Readonly<Pick<CookieParams, 'cookieName' | 'hostOrigin' | 'isDev'>>,
|
|
189
|
+
overrides: PartialWithUndefined<{
|
|
190
|
+
csrfHeaderName: CsrfHeaderName;
|
|
191
|
+
}> = {},
|
|
192
|
+
): {
|
|
193
|
+
'set-cookie': string;
|
|
194
|
+
} & Record<CsrfHeaderName, string> {
|
|
195
|
+
const csrfHeaderName = (overrides.csrfHeaderName || AuthHeaderName.CsrfToken) as CsrfHeaderName;
|
|
196
|
+
|
|
128
197
|
return {
|
|
129
|
-
'set-cookie': clearAuthCookie(
|
|
130
|
-
[
|
|
131
|
-
}
|
|
198
|
+
'set-cookie': clearAuthCookie(cookieConfig),
|
|
199
|
+
[csrfHeaderName]: 'redacted',
|
|
200
|
+
} as {
|
|
201
|
+
'set-cookie': string;
|
|
202
|
+
} & Record<CsrfHeaderName, string>;
|
|
132
203
|
}
|
|
133
204
|
|
|
134
205
|
/**
|
|
@@ -142,77 +213,28 @@ export function generateLogoutHeaders(...params: Parameters<typeof clearAuthCook
|
|
|
142
213
|
*/
|
|
143
214
|
export function handleAuthResponse(
|
|
144
215
|
response: Readonly<Pick<Response, 'ok' | 'headers'>>,
|
|
145
|
-
overrides: {
|
|
216
|
+
overrides: PartialWithUndefined<{
|
|
146
217
|
/**
|
|
147
218
|
* Allows mocking or overriding the global `localStorage`.
|
|
148
219
|
*
|
|
149
220
|
* @default globalThis.localStorage
|
|
150
221
|
*/
|
|
151
|
-
localStorage
|
|
222
|
+
localStorage: Pick<Storage, 'setItem' | 'removeItem'>;
|
|
152
223
|
/** Override the default CSRF token header name. */
|
|
153
|
-
csrfHeaderName
|
|
154
|
-
} = {},
|
|
224
|
+
csrfHeaderName: string;
|
|
225
|
+
}> = {},
|
|
155
226
|
) {
|
|
156
227
|
if (!response.ok) {
|
|
157
228
|
wipeCurrentCsrfToken(overrides);
|
|
158
229
|
return;
|
|
159
230
|
}
|
|
160
|
-
const headerName = overrides.csrfHeaderName || csrfTokenHeaderName;
|
|
161
231
|
|
|
162
|
-
const csrfToken = response
|
|
232
|
+
const {csrfToken} = extractCsrfTokenHeader(response, overrides);
|
|
163
233
|
|
|
164
234
|
if (!csrfToken) {
|
|
165
235
|
wipeCurrentCsrfToken(overrides);
|
|
166
236
|
throw new Error('Did not receive any CSRF token.');
|
|
167
237
|
}
|
|
168
238
|
|
|
169
|
-
(
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Used in client (frontend) code to retrieve the current CSRF token in order to send it with
|
|
174
|
-
* requests to the host (backend).
|
|
175
|
-
*
|
|
176
|
-
* @category Auth : Client
|
|
177
|
-
*/
|
|
178
|
-
export function getCurrentCsrfToken(
|
|
179
|
-
overrides: {
|
|
180
|
-
/**
|
|
181
|
-
* Allows mocking or overriding the global `localStorage`.
|
|
182
|
-
*
|
|
183
|
-
* @default globalThis.localStorage
|
|
184
|
-
*/
|
|
185
|
-
localStorage?: Pick<Storage, 'getItem'>;
|
|
186
|
-
/** Override the default CSRF token header name. */
|
|
187
|
-
csrfHeaderName?: string;
|
|
188
|
-
} = {},
|
|
189
|
-
): string | undefined {
|
|
190
|
-
return (
|
|
191
|
-
(overrides.localStorage || globalThis.localStorage).getItem(
|
|
192
|
-
overrides.csrfHeaderName || csrfTokenHeaderName,
|
|
193
|
-
) || undefined
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Wipes the current stored CSRF token. This should be used by client (frontend) code to logout a
|
|
199
|
-
* user or react to a session timeout.
|
|
200
|
-
*
|
|
201
|
-
* @category Auth : Client
|
|
202
|
-
*/
|
|
203
|
-
export function wipeCurrentCsrfToken(
|
|
204
|
-
overrides: {
|
|
205
|
-
/**
|
|
206
|
-
* Allows mocking or overriding the global `localStorage`.
|
|
207
|
-
*
|
|
208
|
-
* @default globalThis.localStorage
|
|
209
|
-
*/
|
|
210
|
-
localStorage?: Pick<Storage, 'removeItem'>;
|
|
211
|
-
/** Override the default CSRF token header name. */
|
|
212
|
-
csrfHeaderName?: string;
|
|
213
|
-
} = {},
|
|
214
|
-
) {
|
|
215
|
-
return (overrides.localStorage || globalThis.localStorage).removeItem(
|
|
216
|
-
overrides.csrfHeaderName || csrfTokenHeaderName,
|
|
217
|
-
);
|
|
239
|
+
storeCsrfToken(csrfToken, overrides);
|
|
218
240
|
}
|
package/src/cookie.ts
CHANGED
|
@@ -3,8 +3,20 @@ import {safeMatch, type PartialWithUndefined} from '@augment-vir/common';
|
|
|
3
3
|
import {convertDuration, type AnyDuration} from 'date-vir';
|
|
4
4
|
import {type Primitive} from 'type-fest';
|
|
5
5
|
import {parseUrl} from 'url-vir';
|
|
6
|
-
import {type CreateJwtParams, type ParseJwtParams} from './jwt/jwt.js';
|
|
7
|
-
import {createUserJwt, parseUserJwt, type
|
|
6
|
+
import {type CreateJwtParams, type ParseJwtParams, type ParsedJwt} from './jwt/jwt.js';
|
|
7
|
+
import {createUserJwt, parseUserJwt, type JwtUserData} from './jwt/user-jwt.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Cookie header names supported by default.
|
|
11
|
+
*
|
|
12
|
+
* @category Internal
|
|
13
|
+
*/
|
|
14
|
+
export enum AuthCookieName {
|
|
15
|
+
/** Used for a full user login auth. */
|
|
16
|
+
Auth = 'auth',
|
|
17
|
+
/** Use for a temporary "just signed up" auth. */
|
|
18
|
+
SignUp = 'sign-up',
|
|
19
|
+
}
|
|
8
20
|
|
|
9
21
|
/**
|
|
10
22
|
* Parameters for {@link generateAuthCookie}.
|
|
@@ -47,7 +59,7 @@ export type CookieParams = {
|
|
|
47
59
|
* @category Internal
|
|
48
60
|
*/
|
|
49
61
|
export async function generateAuthCookie(
|
|
50
|
-
userJwtData: Readonly<
|
|
62
|
+
userJwtData: Readonly<JwtUserData>,
|
|
51
63
|
cookieConfig: Readonly<CookieParams>,
|
|
52
64
|
): Promise<string> {
|
|
53
65
|
return generateCookie({
|
|
@@ -122,17 +134,17 @@ export function generateCookie(
|
|
|
122
134
|
export async function extractCookieJwt(
|
|
123
135
|
rawCookie: string,
|
|
124
136
|
jwtParams: Readonly<ParseJwtParams>,
|
|
125
|
-
cookieName: string =
|
|
126
|
-
): Promise<undefined |
|
|
137
|
+
cookieName: string = AuthCookieName.Auth,
|
|
138
|
+
): Promise<undefined | ParsedJwt<JwtUserData>> {
|
|
127
139
|
const cookieRegExp = new RegExp(`${cookieName}=[^;]+(?:;|$)`);
|
|
128
140
|
|
|
129
|
-
const [
|
|
141
|
+
const [cookieValue] = safeMatch(rawCookie, cookieRegExp);
|
|
130
142
|
|
|
131
|
-
if (!
|
|
143
|
+
if (!cookieValue) {
|
|
132
144
|
return undefined;
|
|
133
145
|
}
|
|
134
146
|
|
|
135
|
-
const rawJwt =
|
|
147
|
+
const rawJwt = cookieValue.replace(`${cookieName}=`, '').replace(';', '');
|
|
136
148
|
|
|
137
149
|
const jwt = await parseUserJwt(rawJwt, jwtParams);
|
|
138
150
|
|
package/src/csrf-token.ts
CHANGED
|
@@ -1,17 +1,208 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
randomString,
|
|
3
|
+
wrapInTry,
|
|
4
|
+
type PartialWithUndefined,
|
|
5
|
+
type SelectFrom,
|
|
6
|
+
} from '@augment-vir/common';
|
|
7
|
+
import {
|
|
8
|
+
calculateRelativeDate,
|
|
9
|
+
fullDateShape,
|
|
10
|
+
getNowInUtcTimezone,
|
|
11
|
+
isDateAfter,
|
|
12
|
+
type AnyDuration,
|
|
13
|
+
} from 'date-vir';
|
|
14
|
+
import {defineShape, parseJsonWithShape} from 'object-shape-tester';
|
|
15
|
+
import {type RequireExactlyOne} from 'type-fest';
|
|
16
|
+
import {AuthHeaderName} from './headers.js';
|
|
2
17
|
|
|
3
18
|
/**
|
|
4
|
-
*
|
|
19
|
+
* Shape definition for {@link CsrfToken}.
|
|
5
20
|
*
|
|
6
21
|
* @category Internal
|
|
7
22
|
*/
|
|
8
|
-
export const
|
|
23
|
+
export const csrfTokenShape = defineShape({
|
|
24
|
+
token: '',
|
|
25
|
+
expiration: fullDateShape,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* A cryptographically CSRF token with expiration date.
|
|
30
|
+
*
|
|
31
|
+
* @category Internal
|
|
32
|
+
*/
|
|
33
|
+
export type CsrfToken = typeof csrfTokenShape.runtimeType;
|
|
9
34
|
|
|
10
35
|
/**
|
|
11
36
|
* Generates a random, cryptographically secure CSRF token.
|
|
12
37
|
*
|
|
13
38
|
* @category Internal
|
|
14
39
|
*/
|
|
15
|
-
export function generateCsrfToken(
|
|
16
|
-
|
|
40
|
+
export function generateCsrfToken(
|
|
41
|
+
/** How long the CSRF token is valid for. */
|
|
42
|
+
duration: Readonly<AnyDuration>,
|
|
43
|
+
): CsrfToken {
|
|
44
|
+
return {
|
|
45
|
+
token: randomString(256),
|
|
46
|
+
expiration: calculateRelativeDate(getNowInUtcTimezone(), duration),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* CSRF token failure reasons for {@link GetCsrfTokenResult}.
|
|
52
|
+
*
|
|
53
|
+
* @category Internal
|
|
54
|
+
*/
|
|
55
|
+
export enum CsrfTokenFailureReason {
|
|
56
|
+
/** No CSRF token was found. */
|
|
57
|
+
DoesNotExist = 'does-not-exist',
|
|
58
|
+
/** A CSRF token was found but parsing it failed. */
|
|
59
|
+
ParseFailed = 'parse-failed',
|
|
60
|
+
/** A CSRF token was found and parsed but is expired. */
|
|
61
|
+
Expired = 'expired',
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Output from {@link getCurrentCsrfToken}.
|
|
66
|
+
*
|
|
67
|
+
* @category Internal
|
|
68
|
+
*/
|
|
69
|
+
export type GetCsrfTokenResult = RequireExactlyOne<{
|
|
70
|
+
csrfToken: Readonly<CsrfToken>;
|
|
71
|
+
failure: CsrfTokenFailureReason;
|
|
72
|
+
}>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Extract the CSRF token header from a response.
|
|
76
|
+
*
|
|
77
|
+
* @category Auth : Client
|
|
78
|
+
*/
|
|
79
|
+
export function extractCsrfTokenHeader(
|
|
80
|
+
response: Readonly<SelectFrom<Response, {headers: true}>>,
|
|
81
|
+
overrides: PartialWithUndefined<{
|
|
82
|
+
csrfHeaderName: string;
|
|
83
|
+
}> = {},
|
|
84
|
+
): Readonly<GetCsrfTokenResult> {
|
|
85
|
+
const csrfTokenHeaderName = overrides.csrfHeaderName || AuthHeaderName.CsrfToken;
|
|
86
|
+
|
|
87
|
+
const rawCsrfToken = response.headers.get(csrfTokenHeaderName);
|
|
88
|
+
|
|
89
|
+
return parseCsrfToken(rawCsrfToken);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Stores the given CSRF token into local storage.
|
|
94
|
+
*
|
|
95
|
+
* @category Auth : Client
|
|
96
|
+
*/
|
|
97
|
+
export function storeCsrfToken(
|
|
98
|
+
csrfToken: Readonly<CsrfToken>,
|
|
99
|
+
overrides: PartialWithUndefined<{
|
|
100
|
+
/**
|
|
101
|
+
* Allows mocking or overriding the global `localStorage`.
|
|
102
|
+
*
|
|
103
|
+
* @default globalThis.localStorage
|
|
104
|
+
*/
|
|
105
|
+
localStorage: Pick<Storage, 'setItem' | 'removeItem'>;
|
|
106
|
+
/** Override the default CSRF token header name. */
|
|
107
|
+
csrfHeaderName: string;
|
|
108
|
+
}> = {},
|
|
109
|
+
) {
|
|
110
|
+
(overrides.localStorage || globalThis.localStorage).setItem(
|
|
111
|
+
overrides.csrfHeaderName || AuthHeaderName.CsrfToken,
|
|
112
|
+
JSON.stringify(csrfToken),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Parse a raw CSRF token JSON string.
|
|
118
|
+
*
|
|
119
|
+
* @category Internal
|
|
120
|
+
*/
|
|
121
|
+
export function parseCsrfToken(value: string | undefined | null): Readonly<GetCsrfTokenResult> {
|
|
122
|
+
if (!value) {
|
|
123
|
+
return {
|
|
124
|
+
failure: CsrfTokenFailureReason.DoesNotExist,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const csrfToken: CsrfToken | undefined = wrapInTry(
|
|
129
|
+
() =>
|
|
130
|
+
parseJsonWithShape(value, csrfTokenShape, {
|
|
131
|
+
/** For forwards / backwards compatibility. */
|
|
132
|
+
allowExtraKeys: true,
|
|
133
|
+
}),
|
|
134
|
+
{
|
|
135
|
+
fallbackValue: undefined,
|
|
136
|
+
},
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
if (!csrfToken) {
|
|
140
|
+
return {
|
|
141
|
+
failure: CsrfTokenFailureReason.ParseFailed,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (
|
|
146
|
+
isDateAfter({
|
|
147
|
+
fullDate: getNowInUtcTimezone(),
|
|
148
|
+
relativeTo: csrfToken.expiration,
|
|
149
|
+
})
|
|
150
|
+
) {
|
|
151
|
+
return {
|
|
152
|
+
failure: CsrfTokenFailureReason.Expired,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
csrfToken,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Used in client (frontend) code to retrieve the current CSRF token in order to send it with
|
|
163
|
+
* requests to the host (backend).
|
|
164
|
+
*
|
|
165
|
+
* @category Auth : Client
|
|
166
|
+
*/
|
|
167
|
+
export function getCurrentCsrfToken(
|
|
168
|
+
overrides: PartialWithUndefined<{
|
|
169
|
+
/**
|
|
170
|
+
* Allows mocking or overriding the global `localStorage`.
|
|
171
|
+
*
|
|
172
|
+
* @default globalThis.localStorage
|
|
173
|
+
*/
|
|
174
|
+
localStorage: Pick<Storage, 'getItem'>;
|
|
175
|
+
/** Override the default CSRF token header name. */
|
|
176
|
+
csrfHeaderName: string;
|
|
177
|
+
}> = {},
|
|
178
|
+
): Readonly<GetCsrfTokenResult> {
|
|
179
|
+
const rawCsrfToken: string | undefined =
|
|
180
|
+
(overrides.localStorage || globalThis.localStorage).getItem(
|
|
181
|
+
overrides.csrfHeaderName || AuthHeaderName.CsrfToken,
|
|
182
|
+
) || undefined;
|
|
183
|
+
|
|
184
|
+
return parseCsrfToken(rawCsrfToken);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Wipes the current stored CSRF token. This should be used by client (frontend) code to logout a
|
|
189
|
+
* user or react to a session timeout.
|
|
190
|
+
*
|
|
191
|
+
* @category Auth : Client
|
|
192
|
+
*/
|
|
193
|
+
export function wipeCurrentCsrfToken(
|
|
194
|
+
overrides: PartialWithUndefined<{
|
|
195
|
+
/**
|
|
196
|
+
* Allows mocking or overriding the global `localStorage`.
|
|
197
|
+
*
|
|
198
|
+
* @default globalThis.localStorage
|
|
199
|
+
*/
|
|
200
|
+
localStorage: Pick<Storage, 'removeItem'>;
|
|
201
|
+
/** Override the default CSRF token header name. */
|
|
202
|
+
csrfHeaderName: string;
|
|
203
|
+
}> = {},
|
|
204
|
+
) {
|
|
205
|
+
return (overrides.localStorage || globalThis.localStorage).removeItem(
|
|
206
|
+
overrides.csrfHeaderName || AuthHeaderName.CsrfToken,
|
|
207
|
+
);
|
|
17
208
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
// @ts-nocheck
|
|
5
|
+
/*
|
|
6
|
+
* This file should be your main import to use Prisma-related types and utilities in a browser.
|
|
7
|
+
* Use it to get access to models, enums, and input types.
|
|
8
|
+
*
|
|
9
|
+
* This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only.
|
|
10
|
+
* See `client.ts` for the standard, server-side entry point.
|
|
11
|
+
*
|
|
12
|
+
* 🟢 You can import this file directly.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import * as Prisma from './internal/prismaNamespaceBrowser.js'
|
|
16
|
+
export { Prisma }
|
|
17
|
+
export * as $Enums from './enums.js'
|
|
18
|
+
export * from './enums.js';
|
|
19
|
+
/**
|
|
20
|
+
* Model User
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
export type User = Prisma.UserModel
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
|
|
2
|
+
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
|
3
|
+
/* eslint-disable */
|
|
4
|
+
// @ts-nocheck
|
|
5
|
+
/*
|
|
6
|
+
* This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types.
|
|
7
|
+
* If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead.
|
|
8
|
+
*
|
|
9
|
+
* 🟢 You can import this file directly.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import * as process from 'node:process'
|
|
13
|
+
import * as path from 'node:path'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
globalThis['__dirname'] = path.dirname(fileURLToPath(import.meta.url))
|
|
16
|
+
|
|
17
|
+
import * as runtime from "@prisma/client/runtime/client"
|
|
18
|
+
import * as $Enums from "./enums.js"
|
|
19
|
+
import * as $Class from "./internal/class.js"
|
|
20
|
+
import * as Prisma from "./internal/prismaNamespace.js"
|
|
21
|
+
|
|
22
|
+
export * as $Enums from './enums.js'
|
|
23
|
+
export * from "./enums.js"
|
|
24
|
+
/**
|
|
25
|
+
* ## Prisma Client
|
|
26
|
+
*
|
|
27
|
+
* Type-safe database client for TypeScript
|
|
28
|
+
* @example
|
|
29
|
+
* ```
|
|
30
|
+
* const prisma = new PrismaClient()
|
|
31
|
+
* // Fetch zero or more Users
|
|
32
|
+
* const users = await prisma.user.findMany()
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client).
|
|
36
|
+
*/
|
|
37
|
+
export const PrismaClient = $Class.getPrismaClientClass(__dirname)
|
|
38
|
+
export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
|
39
|
+
export { Prisma }
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Model User
|
|
45
|
+
*
|
|
46
|
+
*/
|
|
47
|
+
export type User = Prisma.UserModel
|