@electr0zed/auth-gateway-cf 0.1.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.
Files changed (110) hide show
  1. package/README.md +59 -0
  2. package/dist/auth/index.d.ts +84 -0
  3. package/dist/auth/index.d.ts.map +1 -0
  4. package/dist/auth/index.js +609 -0
  5. package/dist/auth/index.js.map +1 -0
  6. package/dist/auth/pkceState.d.ts +40 -0
  7. package/dist/auth/pkceState.d.ts.map +1 -0
  8. package/dist/auth/pkceState.js +75 -0
  9. package/dist/auth/pkceState.js.map +1 -0
  10. package/dist/config.example.d.ts +2 -0
  11. package/dist/config.example.d.ts.map +1 -0
  12. package/dist/config.example.js +83 -0
  13. package/dist/config.example.js.map +1 -0
  14. package/dist/core/gateway.d.ts +11 -0
  15. package/dist/core/gateway.d.ts.map +1 -0
  16. package/dist/core/gateway.js +97 -0
  17. package/dist/core/gateway.js.map +1 -0
  18. package/dist/do/sessionDo.d.ts +11 -0
  19. package/dist/do/sessionDo.d.ts.map +1 -0
  20. package/dist/do/sessionDo.js +96 -0
  21. package/dist/do/sessionDo.js.map +1 -0
  22. package/dist/index.d.ts +7 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +16 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/providers/baseProvider.d.ts +22 -0
  27. package/dist/providers/baseProvider.d.ts.map +1 -0
  28. package/dist/providers/baseProvider.js +129 -0
  29. package/dist/providers/baseProvider.js.map +1 -0
  30. package/dist/providers/google.d.ts +9 -0
  31. package/dist/providers/google.d.ts.map +1 -0
  32. package/dist/providers/google.js +27 -0
  33. package/dist/providers/google.js.map +1 -0
  34. package/dist/providers/index.d.ts +3 -0
  35. package/dist/providers/index.d.ts.map +1 -0
  36. package/dist/providers/index.js +5 -0
  37. package/dist/providers/index.js.map +1 -0
  38. package/dist/routing/routeMatcher.d.ts +15 -0
  39. package/dist/routing/routeMatcher.d.ts.map +1 -0
  40. package/dist/routing/routeMatcher.js +83 -0
  41. package/dist/routing/routeMatcher.js.map +1 -0
  42. package/dist/sessions/durableObjectSession.d.ts +25 -0
  43. package/dist/sessions/durableObjectSession.d.ts.map +1 -0
  44. package/dist/sessions/durableObjectSession.js +90 -0
  45. package/dist/sessions/durableObjectSession.js.map +1 -0
  46. package/dist/sessions/index.d.ts +19 -0
  47. package/dist/sessions/index.d.ts.map +1 -0
  48. package/dist/sessions/index.js +32 -0
  49. package/dist/sessions/index.js.map +1 -0
  50. package/dist/sessions/jwtSession.d.ts +19 -0
  51. package/dist/sessions/jwtSession.d.ts.map +1 -0
  52. package/dist/sessions/jwtSession.js +49 -0
  53. package/dist/sessions/jwtSession.js.map +1 -0
  54. package/dist/stores/index.d.ts +3 -0
  55. package/dist/stores/index.d.ts.map +1 -0
  56. package/dist/stores/index.js +10 -0
  57. package/dist/stores/index.js.map +1 -0
  58. package/dist/stores/postgres.d.ts +74 -0
  59. package/dist/stores/postgres.d.ts.map +1 -0
  60. package/dist/stores/postgres.js +231 -0
  61. package/dist/stores/postgres.js.map +1 -0
  62. package/dist/types.d.ts +247 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +5 -0
  65. package/dist/types.js.map +1 -0
  66. package/dist/utils/csrf.d.ts +13 -0
  67. package/dist/utils/csrf.d.ts.map +1 -0
  68. package/dist/utils/csrf.js +42 -0
  69. package/dist/utils/csrf.js.map +1 -0
  70. package/dist/utils/helpers.d.ts +8 -0
  71. package/dist/utils/helpers.d.ts.map +1 -0
  72. package/dist/utils/helpers.js +22 -0
  73. package/dist/utils/helpers.js.map +1 -0
  74. package/dist/utils/http.d.ts +9 -0
  75. package/dist/utils/http.d.ts.map +1 -0
  76. package/dist/utils/http.js +23 -0
  77. package/dist/utils/http.js.map +1 -0
  78. package/dist/utils/jwt.d.ts +22 -0
  79. package/dist/utils/jwt.d.ts.map +1 -0
  80. package/dist/utils/jwt.js +96 -0
  81. package/dist/utils/jwt.js.map +1 -0
  82. package/dist/utils/passwordPolicy.d.ts +9 -0
  83. package/dist/utils/passwordPolicy.d.ts.map +1 -0
  84. package/dist/utils/passwordPolicy.js +29 -0
  85. package/dist/utils/passwordPolicy.js.map +1 -0
  86. package/dist/utils/passwords.d.ts +33 -0
  87. package/dist/utils/passwords.d.ts.map +1 -0
  88. package/dist/utils/passwords.js +139 -0
  89. package/dist/utils/passwords.js.map +1 -0
  90. package/dist/utils/propagation.d.ts +30 -0
  91. package/dist/utils/propagation.d.ts.map +1 -0
  92. package/dist/utils/propagation.js +60 -0
  93. package/dist/utils/propagation.js.map +1 -0
  94. package/dist/utils/returnTo.d.ts +2 -0
  95. package/dist/utils/returnTo.d.ts.map +1 -0
  96. package/dist/utils/returnTo.js +21 -0
  97. package/dist/utils/returnTo.js.map +1 -0
  98. package/dist/utils/roles.d.ts +3 -0
  99. package/dist/utils/roles.d.ts.map +1 -0
  100. package/dist/utils/roles.js +25 -0
  101. package/dist/utils/roles.js.map +1 -0
  102. package/dist/utils/turnstile.d.ts +12 -0
  103. package/dist/utils/turnstile.d.ts.map +1 -0
  104. package/dist/utils/turnstile.js +40 -0
  105. package/dist/utils/turnstile.js.map +1 -0
  106. package/dist/utils/verifyInternal.d.ts +8 -0
  107. package/dist/utils/verifyInternal.d.ts.map +1 -0
  108. package/dist/utils/verifyInternal.js +69 -0
  109. package/dist/utils/verifyInternal.js.map +1 -0
  110. package/package.json +48 -0
@@ -0,0 +1,231 @@
1
+ import { Pool } from 'pg';
2
+ import { Kysely, PostgresDialect } from 'kysely';
3
+ export class PostgresUserStore {
4
+ pool;
5
+ db;
6
+ constructor(hyperdrive) {
7
+ this.pool = new Pool({
8
+ connectionString: hyperdrive.connectionString,
9
+ max: 5, // keep small in Workers
10
+ });
11
+ this.db = new Kysely({
12
+ dialect: new PostgresDialect({ pool: this.pool }),
13
+ });
14
+ }
15
+ async findUserIdByIdentity(issuer, subject) {
16
+ const row = await this.db
17
+ .selectFrom('user_identities as ui')
18
+ .innerJoin('users as u', 'u.id', 'ui.user_id')
19
+ .select(['u.id'])
20
+ .where('ui.issuer', '=', issuer)
21
+ .where('ui.subject', '=', subject)
22
+ .executeTakeFirst();
23
+ return row?.id ?? null;
24
+ // (Optional) .execute() returns array; .executeTakeFirst() returns a single row or undefined.
25
+ }
26
+ async findUserIdByEmail(email) {
27
+ const row = await this.db.selectFrom('users').select('id').where('email', '=', email).executeTakeFirst();
28
+ return row?.id ?? null;
29
+ }
30
+ async createUserWithIdentity(email, identity, generateUsernameFunc) {
31
+ return this.db.transaction().execute(async (trx) => {
32
+ if (await this.checkEmailExists(email)) {
33
+ throw new Error('email_in_use');
34
+ }
35
+ let username = null;
36
+ if (generateUsernameFunc) {
37
+ let attempts = 0;
38
+ while (attempts < 5) {
39
+ const generated = generateUsernameFunc(email);
40
+ if (!(await this.checkUsernameExists(generated))) {
41
+ username = generated;
42
+ break;
43
+ }
44
+ attempts++;
45
+ }
46
+ if (!username) {
47
+ throw new Error('username_generation_failed');
48
+ }
49
+ }
50
+ // 1) Create-or-detect user by email
51
+ const insertedUser = await this.createUser(trx, email, username);
52
+ const userId = insertedUser?.id;
53
+ if (!userId) {
54
+ throw new Error('account_exists');
55
+ }
56
+ // 2) Bind identity. If (issuer, subject) owned by another user, fail.
57
+ const insertedIdentity = await trx
58
+ .insertInto('user_identities')
59
+ .values({
60
+ user_id: userId,
61
+ provider: identity.provider,
62
+ issuer: identity.issuer,
63
+ subject: identity.subject,
64
+ })
65
+ .onConflict((oc) => oc.columns(['issuer', 'subject']).doNothing())
66
+ .returning(['user_id'])
67
+ .executeTakeFirst();
68
+ if (!insertedIdentity) {
69
+ // Conflict → check owner
70
+ const owner = await trx
71
+ .selectFrom('user_identities')
72
+ .select(['user_id'])
73
+ .where('issuer', '=', identity.issuer)
74
+ .where('subject', '=', identity.subject)
75
+ .executeTakeFirst();
76
+ if (owner?.user_id && owner.user_id !== userId) {
77
+ throw new Error('account_exists');
78
+ }
79
+ // else already linked to this user → idempotent
80
+ }
81
+ // 3) Create user_states row
82
+ await this.createUserStates(trx, userId);
83
+ return userId;
84
+ });
85
+ }
86
+ async addIdentityToUser(userId, identity) {
87
+ const res = await this.db
88
+ .insertInto('user_identities')
89
+ .values({
90
+ user_id: userId,
91
+ provider: identity.provider,
92
+ issuer: identity.issuer,
93
+ subject: identity.subject,
94
+ })
95
+ .onConflict((oc) => oc.columns(['issuer', 'subject']).doNothing())
96
+ .returning(['user_id'])
97
+ .executeTakeFirst();
98
+ if (!res) {
99
+ // Conflict → figure out owner
100
+ const owner = await this.db
101
+ .selectFrom('user_identities')
102
+ .select(['user_id'])
103
+ .where('issuer', '=', identity.issuer)
104
+ .where('subject', '=', identity.subject)
105
+ .executeTakeFirst();
106
+ if (owner?.user_id && owner.user_id !== userId) {
107
+ throw new Error('identity_taken');
108
+ }
109
+ // already linked to same user → no-op
110
+ }
111
+ }
112
+ async getUserRoles(userId) {
113
+ const row = await this.db.selectFrom('users').select('system_roles').where('id', '=', userId).executeTakeFirst();
114
+ return row?.system_roles ?? [];
115
+ }
116
+ async getUserStates(userId) {
117
+ const row = await this.db.selectFrom('user_states').selectAll().where('user_id', '=', userId).executeTakeFirst();
118
+ return row || null;
119
+ }
120
+ async createUser(trx, email, username = null) {
121
+ try {
122
+ return await trx
123
+ .insertInto('users')
124
+ .values({ email, username })
125
+ .onConflict((oc) => oc.column('email').doNothing())
126
+ .returning(['id'])
127
+ .executeTakeFirst();
128
+ }
129
+ catch (err) {
130
+ // Normalize unique-constraint violations so callers can distinguish causes.
131
+ // Postgres uses SQLSTATE '23505' for unique_violation errors.
132
+ if (err && typeof err === 'object' && 'code' in err && err.code === '23505') {
133
+ const constraint = 'constraint' in err ? err.constraint : undefined;
134
+ if (typeof constraint === 'string') {
135
+ if (constraint.includes('email')) {
136
+ throw new Error('email_in_use');
137
+ }
138
+ if (constraint.includes('username')) {
139
+ throw new Error('username_in_use');
140
+ }
141
+ }
142
+ }
143
+ throw err;
144
+ }
145
+ }
146
+ async createUserStates(trx, userId) {
147
+ await trx
148
+ .insertInto('user_states')
149
+ .values({
150
+ user_id: userId,
151
+ is_disabled: false,
152
+ disabled_at: null,
153
+ disabled_by: null,
154
+ is_approved: false,
155
+ approved_at: null,
156
+ approved_by: null,
157
+ is_email_verified: false,
158
+ email_verified_at: null,
159
+ email_verification_token_hash: null,
160
+ created_at: new Date(),
161
+ updated_at: new Date(),
162
+ })
163
+ .execute();
164
+ }
165
+ async createUserWithPassword(email, passwordHash, username = null) {
166
+ return this.db.transaction().execute(async (trx) => {
167
+ if (await this.checkEmailExists(email)) {
168
+ throw new Error('email_in_use');
169
+ }
170
+ if (username && (await this.checkUsernameExists(username))) {
171
+ throw new Error('username_in_use');
172
+ }
173
+ // Create user (email unique). If it already exists -> account_exists
174
+ const insertedUser = await this.createUser(trx, email, username);
175
+ const userId = insertedUser?.id;
176
+ if (!userId) {
177
+ throw new Error('account_exists');
178
+ }
179
+ // Set password
180
+ await trx
181
+ .insertInto('user_passwords')
182
+ .values({
183
+ user_id: userId,
184
+ password_hash: passwordHash,
185
+ })
186
+ .execute();
187
+ // Create user_states row
188
+ await this.createUserStates(trx, userId);
189
+ return userId;
190
+ });
191
+ }
192
+ async getUserIdByEmailForPassword(email) {
193
+ const row = await this.db
194
+ .selectFrom('users as u')
195
+ .innerJoin('user_passwords as up', 'up.user_id', 'u.id')
196
+ .select(['u.id as userId', 'up.password_hash as passwordHash'])
197
+ .where('u.email', '=', email)
198
+ .executeTakeFirst();
199
+ return row ?? null;
200
+ }
201
+ async getPasswordHashByUserId(userId) {
202
+ const row = await this.db.selectFrom('user_passwords').select(['password_hash']).where('user_id', '=', userId).executeTakeFirst();
203
+ return row?.password_hash ?? null;
204
+ }
205
+ async setPasswordHash(userId, passwordHash) {
206
+ await this.db
207
+ .insertInto('user_passwords')
208
+ .values({
209
+ user_id: userId,
210
+ password_hash: passwordHash,
211
+ })
212
+ .onConflict((oc) => oc.column('user_id').doUpdateSet({
213
+ password_hash: passwordHash,
214
+ updated_at: new Date(),
215
+ }))
216
+ .execute();
217
+ }
218
+ async checkUsernameExists(username) {
219
+ const row = await this.db.selectFrom('users').select('id').where('username', '=', username).executeTakeFirst();
220
+ return !!row;
221
+ }
222
+ async checkEmailExists(email) {
223
+ const row = await this.db.selectFrom('users').select('id').where('email', '=', email).executeTakeFirst();
224
+ return !!row;
225
+ }
226
+ async destroy() {
227
+ await this.db.destroy();
228
+ await this.pool.end();
229
+ }
230
+ }
231
+ //# sourceMappingURL=postgres.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../src/stores/postgres.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,247 @@
1
+ import type { DB } from './stores/postgres';
2
+ export type RouteMatch = {
3
+ path: string | RegExp;
4
+ host?: string | RegExp;
5
+ methods?: string[];
6
+ };
7
+ export type RouteRule = {
8
+ name?: string;
9
+ match: RouteMatch | RouteMatch[];
10
+ auth: 'required' | 'none';
11
+ requireRolesAny?: string[];
12
+ requireRolesAll?: string[];
13
+ bypassAuthForStaticAssets?: boolean;
14
+ unauthenticatedRedirectUrl?: string;
15
+ service: Fetcher;
16
+ };
17
+ export type LoginProviderId = 'google';
18
+ export type ProviderConfig = {
19
+ id: LoginProviderId;
20
+ enabled: boolean;
21
+ label?: string;
22
+ clientId: string;
23
+ clientSecretEnv?: string;
24
+ issuer?: string;
25
+ authUrl?: string;
26
+ tokenUrl?: string;
27
+ userInfoUrl?: string;
28
+ scope?: string;
29
+ tenant?: string;
30
+ b2cPolicy?: string;
31
+ };
32
+ /** What each provider must extract from its claims. */
33
+ export type NormalizedClaims = {
34
+ email: string;
35
+ subject: string;
36
+ };
37
+ export type ClaimsMode = 'id_token' | 'userinfo';
38
+ /** Static wiring for a provider (URLs & defaults). */
39
+ export type ProviderStatic = {
40
+ id: LoginProviderId;
41
+ authorizeEndpoint: string;
42
+ tokenEndpoint: string;
43
+ defaultIssuer: string;
44
+ defaultScope?: string;
45
+ userInfoEndpoint?: string;
46
+ claimsMode: ClaimsMode;
47
+ };
48
+ /** Provider-normalized identity output (minimal) */
49
+ export type ProviderIdentity = {
50
+ email: string;
51
+ provider: LoginProviderId;
52
+ issuer: string;
53
+ subject: string;
54
+ };
55
+ export type SystemRole = string;
56
+ export type SessionStrategyCfg = {
57
+ kind: 'jwt';
58
+ cookieName?: string;
59
+ expMinutes?: number;
60
+ jwtSecretEnv: string;
61
+ } | {
62
+ kind: 'durableObject';
63
+ cookieName?: string;
64
+ doName: DurableObjectNamespace<import('./index').SessionDO>;
65
+ jwtSecretEnv: string;
66
+ idleTtlSec?: number;
67
+ absoluteTtlSec?: number;
68
+ issuer?: string;
69
+ audience?: string;
70
+ };
71
+ /** Minimal persistent session payload */
72
+ export interface StoredSession {
73
+ userId: string;
74
+ email: string;
75
+ systemRoles: SystemRole[];
76
+ createdAt: number;
77
+ updatedAt: number;
78
+ }
79
+ export type Session = {
80
+ userId: string;
81
+ email: string;
82
+ systemRoles: SystemRole[];
83
+ };
84
+ export interface SessionStrategy {
85
+ resolve(request: Request, env: Env): Promise<{
86
+ session: Session | null;
87
+ accessJwt?: string;
88
+ }>;
89
+ issue?(session: Session, env: Env): Promise<{
90
+ cookie?: string;
91
+ accessJwt?: string;
92
+ }>;
93
+ clear?(request: Request, env: Env): Promise<{
94
+ cookie: string;
95
+ }>;
96
+ }
97
+ export type OAuthCfg = {
98
+ enabled: true;
99
+ providers: ProviderConfig[];
100
+ defaultProvider: LoginProviderId;
101
+ successRedirectUrl: string;
102
+ failureRedirectUrl: string;
103
+ } | {
104
+ enabled: false;
105
+ };
106
+ export type PasswordPolicy = {
107
+ minLength: number;
108
+ requireUppercase?: boolean;
109
+ requireLowercase?: boolean;
110
+ requireNumber?: boolean;
111
+ requireSymbol?: boolean;
112
+ };
113
+ export type TurnstileCfg = {
114
+ enabled: true;
115
+ /**
116
+ * Env var that contains the Turnstile secret key.
117
+ * (Configurable like your other secrets)
118
+ */
119
+ secretEnv: string;
120
+ /**
121
+ * JSON field name that carries the token.
122
+ * Default: "turnstileToken"
123
+ */
124
+ tokenField?: string;
125
+ } | {
126
+ enabled: false;
127
+ };
128
+ export type PasswordAuthCfg = {
129
+ enabled: true;
130
+ /**
131
+ * Env var that contains comma-separated peppers (newest first).
132
+ * Example value: "pepper_v2,pepper_v1"
133
+ */
134
+ pepperEnv: string;
135
+ policy?: PasswordPolicy;
136
+ allowSignup: boolean;
137
+ turnstile?: TurnstileCfg;
138
+ } | {
139
+ enabled: false;
140
+ };
141
+ export type ConfigOverrides = {
142
+ staticAssetRegex?: RegExp;
143
+ globalUnauthenticatedRedirectUrl?: string;
144
+ accountApproval?: {
145
+ enabled: boolean;
146
+ };
147
+ emailVerification?: {
148
+ enabled: true;
149
+ requiredForLogin: boolean;
150
+ } | {
151
+ enabled: false;
152
+ };
153
+ autoLoginAfterSignup?: boolean;
154
+ captureUsername?: {
155
+ enabled: true;
156
+ required: true;
157
+ generateFunction?: (email: string) => string;
158
+ minLength?: number;
159
+ } | {
160
+ enabled: true;
161
+ required: false;
162
+ minLength?: number;
163
+ } | {
164
+ enabled: false;
165
+ };
166
+ };
167
+ export type PropagationCfg = {
168
+ headerName?: string;
169
+ sigHeaderName?: string;
170
+ hmacSecretEnv: string;
171
+ };
172
+ type StoreBackend = {
173
+ kind: 'postgres';
174
+ hyperdrive: Hyperdrive;
175
+ };
176
+ export type UserStoreCfg = StoreBackend & {
177
+ shortStateKV: KVNamespace;
178
+ };
179
+ export type ProjectConfig = {
180
+ projectName: string;
181
+ publicBaseUrl: string;
182
+ routes: RouteRule[];
183
+ session: SessionStrategyCfg;
184
+ propagation: PropagationCfg;
185
+ userStore: UserStoreCfg;
186
+ oAuth: OAuthCfg;
187
+ passwordAuth: PasswordAuthCfg;
188
+ overrides?: ConfigOverrides;
189
+ };
190
+ export interface UserCore {
191
+ id: string;
192
+ email: string;
193
+ systemRoles: SystemRole[];
194
+ }
195
+ export interface UserStore {
196
+ findUserIdByIdentity(issuer: string, subject: string): Promise<string | null>;
197
+ findUserIdByEmail(emailLower: string): Promise<string | null>;
198
+ createUserWithIdentity(emailLower: string, identity: {
199
+ provider: string;
200
+ issuer: string;
201
+ subject: string;
202
+ }, generateUsernameFunc?: (email: string) => string): Promise<string>;
203
+ addIdentityToUser(userId: string, identity: {
204
+ provider: string;
205
+ issuer: string;
206
+ subject: string;
207
+ }): Promise<void>;
208
+ getUserRoles(userId: string): Promise<SystemRole[]>;
209
+ getUserStates(userId: string): Promise<DB['user_states'] | null>;
210
+ createUserWithPassword(emailLower: string, passwordHash: string, username?: string | null): Promise<string>;
211
+ getPasswordHashByUserId(userId: string): Promise<string | null>;
212
+ getUserIdByEmailForPassword(emailLower: string): Promise<{
213
+ userId: string;
214
+ passwordHash: string;
215
+ } | null>;
216
+ setPasswordHash(userId: string, passwordHash: string): Promise<void>;
217
+ }
218
+ export type StateMode = 'login' | 'link';
219
+ export type StateInfo = {
220
+ mode: StateMode;
221
+ returnTo?: string;
222
+ provider?: string;
223
+ };
224
+ export type StoredPkce = {
225
+ v: string;
226
+ i: StateInfo;
227
+ };
228
+ export type TokenResponse = {
229
+ access_token?: string;
230
+ id_token?: string;
231
+ refresh_token?: string;
232
+ token_type?: string;
233
+ expires_in?: number;
234
+ [key: string]: unknown;
235
+ };
236
+ declare global {
237
+ interface Env {
238
+ [key: string]: string | undefined;
239
+ }
240
+ }
241
+ export type JwtPrimitive = string | number | boolean | null;
242
+ export type JwtValue = JwtPrimitive | JwtValue[] | {
243
+ [key: string]: JwtValue;
244
+ };
245
+ export type JwtPayload = Record<string, JwtValue>;
246
+ export {};
247
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /* =========================================
2
+ * Routing / Gateway
3
+ * =======================================*/
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;4CAE4C"}
@@ -0,0 +1,13 @@
1
+ export declare function makeCsrfToken(): string;
2
+ export declare function csrfCookie(token: string): string;
3
+ export declare function sameOrigin(request: Request, publicBaseUrl: string): boolean;
4
+ type Obj = Record<string, unknown>;
5
+ export declare function requireCsrfJson<T extends Obj>(request: Request): Promise<{
6
+ ok: true;
7
+ body: T;
8
+ } | {
9
+ ok: false;
10
+ code: string;
11
+ }>;
12
+ export {};
13
+ //# sourceMappingURL=csrf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/utils/csrf.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAS3E;AAED,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAOnC,wBAAsB,eAAe,CAAC,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAYnI"}
@@ -0,0 +1,42 @@
1
+ // src/utils/csrf.ts
2
+ import { getCookie } from '../sessions';
3
+ import { readJson } from './http';
4
+ export function makeCsrfToken() {
5
+ const b = crypto.getRandomValues(new Uint8Array(16));
6
+ return Array.from(b)
7
+ .map((x) => x.toString(16).padStart(2, '0'))
8
+ .join('');
9
+ }
10
+ export function csrfCookie(token) {
11
+ return `__Host-csrf=${token}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600; Priority=Medium`;
12
+ }
13
+ export function sameOrigin(request, publicBaseUrl) {
14
+ const origin = request.headers.get('origin');
15
+ if (!origin)
16
+ return false;
17
+ try {
18
+ return new URL(origin).origin === new URL(publicBaseUrl).origin;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ function getStringField(obj, key) {
25
+ const v = obj[key];
26
+ return typeof v === 'string' ? v : null;
27
+ }
28
+ export async function requireCsrfJson(request) {
29
+ const parsed = await readJson(request);
30
+ if (!parsed.ok)
31
+ return parsed;
32
+ const cookieToken = getCookie(request, '__Host-csrf');
33
+ if (!cookieToken)
34
+ return { ok: false, code: 'csrf_missing' };
35
+ const provided = getStringField(parsed.body, 'csrf');
36
+ if (!provided || provided.length !== 32)
37
+ return { ok: false, code: 'csrf_missing' };
38
+ if (provided !== cookieToken)
39
+ return { ok: false, code: 'csrf_invalid' };
40
+ return parsed;
41
+ }
42
+ //# sourceMappingURL=csrf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/utils/csrf.ts"],"names":[],"mappings":"AAAA,oBAAoB;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAElC,MAAM,UAAU,aAAa;IAC5B,MAAM,CAAC,GAAG,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;SAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACvC,OAAO,eAAe,KAAK,yEAAyE,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAgB,EAAE,aAAqB;IACjE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAE1B,IAAI,CAAC;QACJ,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,IAAI,GAAG,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAID,SAAS,cAAc,CAAC,GAAQ,EAAE,GAAW;IAC5C,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAgB,OAAgB;IACpE,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAI,OAAO,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC;IAE9B,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACtD,IAAI,CAAC,WAAW;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAE7D,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,EAAE;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IACpF,IAAI,QAAQ,KAAK,WAAW;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAEzE,OAAO,MAAM,CAAC;AACf,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const normEmail: (e: string) => string;
2
+ export declare const validateEmail: (email: string) => boolean;
3
+ export declare const usernameRegex: RegExp;
4
+ export declare const normUsername: (u: string) => string;
5
+ export declare const validateUsername: (username: string) => boolean;
6
+ export declare const STATIC_ASSET_RE: RegExp;
7
+ export declare const generateUsername: (_: string) => string;
8
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,WAA2B,CAAC;AAE/D,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,OAE7C,CAAC;AAEF,eAAO,MAAM,aAAa,QAAqB,CAAC;AAEhD,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,WAAa,CAAC;AAEpD,eAAO,MAAM,gBAAgB,GAAI,UAAU,MAAM,KAAG,OAEnD,CAAC;AAEF,eAAO,MAAM,eAAe,QAAoE,CAAC;AAEjG,eAAO,MAAM,gBAAgB,GAAI,GAAG,MAAM,KAAG,MAQ5C,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { uniqueNamesGenerator, adjectives, animals } from 'unique-names-generator';
2
+ const emailRegex = /^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)+$/;
3
+ export const normEmail = (e) => e.trim().toLowerCase();
4
+ export const validateEmail = (email) => {
5
+ return emailRegex.test(email);
6
+ };
7
+ export const usernameRegex = /^[A-Za-z0-9_-]+$/;
8
+ export const normUsername = (u) => u.trim();
9
+ export const validateUsername = (username) => {
10
+ return usernameRegex.test(username);
11
+ };
12
+ export const STATIC_ASSET_RE = /\.(?:css|js|mjs|png|jpg|jpeg|gif|webp|svg|ico|woff2?|ttf|otf)$/i;
13
+ export const generateUsername = (_) => {
14
+ const config = {
15
+ dictionaries: [adjectives, animals],
16
+ separator: '-',
17
+ length: 2,
18
+ style: 'capital',
19
+ };
20
+ return uniqueNamesGenerator(config) + '-' + Math.random().toString(36).substring(2, 6);
21
+ };
22
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAU,UAAU,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAE3F,MAAM,UAAU,GACf,sIAAsI,CAAC;AAExI,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAE/D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAa,EAAW,EAAE;IACvD,OAAO,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,kBAAkB,CAAC;AAEhD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAEpD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAgB,EAAW,EAAE;IAC7D,OAAO,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,iEAAiE,CAAC;AAEjG,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAS,EAAU,EAAE;IACrD,MAAM,MAAM,GAAW;QACtB,YAAY,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC;QACnC,SAAS,EAAE,GAAG;QACd,MAAM,EAAE,CAAC;QACT,KAAK,EAAE,SAAS;KAChB,CAAC;IACF,OAAO,oBAAoB,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxF,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare function json(obj: unknown, init?: ResponseInit): Response;
2
+ export declare function readJson<T = unknown>(request: Request): Promise<{
3
+ ok: true;
4
+ body: T;
5
+ } | {
6
+ ok: false;
7
+ code: string;
8
+ }>;
9
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":"AAEA,wBAAgB,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,GAAE,YAAiB,GAAG,QAAQ,CAQpE;AAED,wBAAsB,QAAQ,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAU1H"}
@@ -0,0 +1,23 @@
1
+ // src/utils/http.ts
2
+ export function json(obj, init = {}) {
3
+ return new Response(JSON.stringify(obj), {
4
+ ...init,
5
+ headers: {
6
+ ...(init.headers ? Object.fromEntries(new Headers(init.headers)) : {}),
7
+ 'content-type': 'application/json',
8
+ },
9
+ });
10
+ }
11
+ export async function readJson(request) {
12
+ const ct = request.headers.get('content-type') || '';
13
+ if (!ct.includes('application/json'))
14
+ return { ok: false, code: 'bad_content_type' };
15
+ try {
16
+ const body = (await request.json());
17
+ return { ok: true, body };
18
+ }
19
+ catch {
20
+ return { ok: false, code: 'bad_json' };
21
+ }
22
+ }
23
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":"AAAA,oBAAoB;AAEpB,MAAM,UAAU,IAAI,CAAC,GAAY,EAAE,OAAqB,EAAE;IACzD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE;QACxC,GAAG,IAAI;QACP,OAAO,EAAE;YACR,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,cAAc,EAAE,kBAAkB;SAClC;KACD,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAc,OAAgB;IAC3D,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;IACrD,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAErF,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAM,CAAC;QACzC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IACxC,CAAC;AACF,CAAC"}