convex-zen 0.0.1
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/dist/cli/generate.d.ts +14 -0
- package/dist/cli/generate.d.ts.map +1 -0
- package/dist/cli/generate.js +297 -0
- package/dist/cli/generate.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +111 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/client/index.d.ts +300 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +434 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/plugins/admin.d.ts +92 -0
- package/dist/client/plugins/admin.d.ts.map +1 -0
- package/dist/client/plugins/admin.js +165 -0
- package/dist/client/plugins/admin.js.map +1 -0
- package/dist/client/primitives.d.ts +57 -0
- package/dist/client/primitives.d.ts.map +1 -0
- package/dist/client/primitives.js +64 -0
- package/dist/client/primitives.js.map +1 -0
- package/dist/client/providers.d.ts +14 -0
- package/dist/client/providers.d.ts.map +1 -0
- package/dist/client/providers.js +25 -0
- package/dist/client/providers.js.map +1 -0
- package/dist/client/react.d.ts +23 -0
- package/dist/client/react.d.ts.map +1 -0
- package/dist/client/react.js +48 -0
- package/dist/client/react.js.map +1 -0
- package/dist/client/tanstack-start-client-plugins.d.ts +34 -0
- package/dist/client/tanstack-start-client-plugins.d.ts.map +1 -0
- package/dist/client/tanstack-start-client-plugins.js +32 -0
- package/dist/client/tanstack-start-client-plugins.js.map +1 -0
- package/dist/client/tanstack-start-client.d.ts +52 -0
- package/dist/client/tanstack-start-client.d.ts.map +1 -0
- package/dist/client/tanstack-start-client.js +130 -0
- package/dist/client/tanstack-start-client.js.map +1 -0
- package/dist/client/tanstack-start-plugins.d.ts +27 -0
- package/dist/client/tanstack-start-plugins.d.ts.map +1 -0
- package/dist/client/tanstack-start-plugins.js +145 -0
- package/dist/client/tanstack-start-plugins.js.map +1 -0
- package/dist/client/tanstack-start.d.ts +130 -0
- package/dist/client/tanstack-start.d.ts.map +1 -0
- package/dist/client/tanstack-start.js +331 -0
- package/dist/client/tanstack-start.js.map +1 -0
- package/dist/component/_generated/api.d.ts +50 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +92 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +4 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/core/sessions.d.ts +33 -0
- package/dist/component/core/sessions.d.ts.map +1 -0
- package/dist/component/core/sessions.js +186 -0
- package/dist/component/core/sessions.js.map +1 -0
- package/dist/component/core/users.d.ts +19 -0
- package/dist/component/core/users.d.ts.map +1 -0
- package/dist/component/core/users.js +154 -0
- package/dist/component/core/users.js.map +1 -0
- package/dist/component/core/verifications.d.ts +34 -0
- package/dist/component/core/verifications.d.ts.map +1 -0
- package/dist/component/core/verifications.js +135 -0
- package/dist/component/core/verifications.js.map +1 -0
- package/dist/component/gateway.d.ts +16 -0
- package/dist/component/gateway.d.ts.map +1 -0
- package/dist/component/gateway.js +229 -0
- package/dist/component/gateway.js.map +1 -0
- package/dist/component/lib/crypto.d.ts +24 -0
- package/dist/component/lib/crypto.d.ts.map +1 -0
- package/dist/component/lib/crypto.js +57 -0
- package/dist/component/lib/crypto.js.map +1 -0
- package/dist/component/lib/rateLimit.d.ts +26 -0
- package/dist/component/lib/rateLimit.d.ts.map +1 -0
- package/dist/component/lib/rateLimit.js +96 -0
- package/dist/component/lib/rateLimit.js.map +1 -0
- package/dist/component/lib/validators.d.ts +19 -0
- package/dist/component/lib/validators.d.ts.map +1 -0
- package/dist/component/lib/validators.js +12 -0
- package/dist/component/lib/validators.js.map +1 -0
- package/dist/component/plugins/admin.d.ts +72 -0
- package/dist/component/plugins/admin.d.ts.map +1 -0
- package/dist/component/plugins/admin.js +152 -0
- package/dist/component/plugins/admin.js.map +1 -0
- package/dist/component/providers/emailPassword.d.ts +49 -0
- package/dist/component/providers/emailPassword.d.ts.map +1 -0
- package/dist/component/providers/emailPassword.js +316 -0
- package/dist/component/providers/emailPassword.js.map +1 -0
- package/dist/component/providers/oauth.d.ts +33 -0
- package/dist/component/providers/oauth.d.ts.map +1 -0
- package/dist/component/providers/oauth.js +256 -0
- package/dist/component/providers/oauth.js.map +1 -0
- package/dist/component/schema.d.ts +132 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +82 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +121 -0
- package/src/cli/generate.ts +360 -0
- package/src/cli/index.ts +133 -0
- package/src/client/index.ts +707 -0
- package/src/client/plugins/admin.ts +205 -0
- package/src/client/primitives.ts +100 -0
- package/src/client/providers.ts +35 -0
- package/src/client/react.ts +97 -0
- package/src/client/tanstack-start-client-plugins.ts +113 -0
- package/src/client/tanstack-start-client.ts +259 -0
- package/src/client/tanstack-start-plugins.ts +203 -0
- package/src/client/tanstack-start.ts +535 -0
- package/src/component/_generated/api.ts +70 -0
- package/src/component/_generated/component.ts +184 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/convex.config.ts +5 -0
- package/src/component/core/sessions.ts +228 -0
- package/src/component/core/users.ts +199 -0
- package/src/component/core/verifications.ts +173 -0
- package/src/component/gateway.ts +321 -0
- package/src/component/lib/crypto.ts +63 -0
- package/src/component/lib/internalApi.ts +66 -0
- package/src/component/lib/rateLimit.ts +111 -0
- package/src/component/lib/validators.ts +12 -0
- package/src/component/plugins/admin.ts +178 -0
- package/src/component/providers/emailPassword.ts +374 -0
- package/src/component/providers/oauth.ts +324 -0
- package/src/component/schema.ts +88 -0
- package/src/types.ts +68 -0
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { argon2id, argon2Verify } from "hash-wasm";
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
import { internalAction, internalMutation } from "../_generated/server";
|
|
4
|
+
import { internal } from "../_generated/api";
|
|
5
|
+
async function hashPassword(password) {
|
|
6
|
+
return argon2id({
|
|
7
|
+
password,
|
|
8
|
+
salt: crypto.getRandomValues(new Uint8Array(16)),
|
|
9
|
+
parallelism: 1,
|
|
10
|
+
iterations: 2,
|
|
11
|
+
memorySize: 19456, // 19 MB in KB
|
|
12
|
+
hashLength: 32,
|
|
13
|
+
outputType: "encoded", // PHC string — includes salt + params
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/** Simple email validation — no ReDoS-prone regex. */
|
|
17
|
+
function isValidEmail(email) {
|
|
18
|
+
if (email.length > 255)
|
|
19
|
+
return false;
|
|
20
|
+
const atIndex = email.indexOf("@");
|
|
21
|
+
if (atIndex < 1)
|
|
22
|
+
return false;
|
|
23
|
+
const domain = email.slice(atIndex + 1);
|
|
24
|
+
if (domain.length < 3)
|
|
25
|
+
return false;
|
|
26
|
+
if (!domain.includes("."))
|
|
27
|
+
return false;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sign up with email and password.
|
|
32
|
+
*
|
|
33
|
+
* Returns the verification code so the host app (via ConvexAuth client)
|
|
34
|
+
* can send the email. Functions cannot be passed as Convex args.
|
|
35
|
+
*
|
|
36
|
+
* Flow:
|
|
37
|
+
* 1. Validate email
|
|
38
|
+
* 2. Check IP rate limit
|
|
39
|
+
* 3. Check email not already registered
|
|
40
|
+
* 4. Hash password with Argon2id
|
|
41
|
+
* 5. Create user + account
|
|
42
|
+
* 6. Generate verification code
|
|
43
|
+
* 7. Return { status: "verification_required", verificationCode }
|
|
44
|
+
*/
|
|
45
|
+
export const signUp = internalAction({
|
|
46
|
+
args: {
|
|
47
|
+
email: v.string(),
|
|
48
|
+
password: v.string(),
|
|
49
|
+
name: v.optional(v.string()),
|
|
50
|
+
ipAddress: v.optional(v.string()),
|
|
51
|
+
},
|
|
52
|
+
handler: async (ctx, args) => {
|
|
53
|
+
const { email, password, name, ipAddress } = args;
|
|
54
|
+
// 1. Validate email
|
|
55
|
+
if (!isValidEmail(email)) {
|
|
56
|
+
throw new Error("Invalid email address");
|
|
57
|
+
}
|
|
58
|
+
// 2. Check IP rate limit
|
|
59
|
+
if (ipAddress) {
|
|
60
|
+
const key = `signup:ip:${ipAddress}`;
|
|
61
|
+
const rateCheck = await ctx.runQuery(internal.lib.rateLimit.check, {
|
|
62
|
+
key,
|
|
63
|
+
});
|
|
64
|
+
if (rateCheck.limited) {
|
|
65
|
+
throw new Error("Too many requests. Please try again later.");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// 3. Check email not already registered
|
|
69
|
+
const existingUser = await ctx.runQuery(internal.core.users.getByEmail, {
|
|
70
|
+
email: email.toLowerCase(),
|
|
71
|
+
});
|
|
72
|
+
if (existingUser) {
|
|
73
|
+
// Increment rate limit to avoid timing-based email enumeration
|
|
74
|
+
if (ipAddress) {
|
|
75
|
+
await ctx.runMutation(internal.lib.rateLimit.increment, {
|
|
76
|
+
key: `signup:ip:${ipAddress}`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
throw new Error("Email already registered");
|
|
80
|
+
}
|
|
81
|
+
// 4. Hash password with Argon2id
|
|
82
|
+
const passwordHash = await hashPassword(password);
|
|
83
|
+
// 5. Create user + account
|
|
84
|
+
const userId = await ctx.runMutation(internal.core.users.create, {
|
|
85
|
+
email: email.toLowerCase(),
|
|
86
|
+
emailVerified: false,
|
|
87
|
+
name,
|
|
88
|
+
});
|
|
89
|
+
await ctx.runMutation(internal.core.users.createAccount, {
|
|
90
|
+
userId,
|
|
91
|
+
providerId: "credential",
|
|
92
|
+
accountId: email.toLowerCase(),
|
|
93
|
+
passwordHash,
|
|
94
|
+
});
|
|
95
|
+
// 6. Generate verification code (returned to caller for email sending)
|
|
96
|
+
const { code, expiresAt } = await ctx.runMutation(internal.core.verifications.create, {
|
|
97
|
+
identifier: email.toLowerCase(),
|
|
98
|
+
type: "email-verification",
|
|
99
|
+
});
|
|
100
|
+
// Schedule cleanup at expiry
|
|
101
|
+
await ctx.scheduler.runAt(expiresAt, internal.core.verifications.cleanup, {});
|
|
102
|
+
return { status: "verification_required", verificationCode: code };
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
/**
|
|
106
|
+
* Sign in with email and password.
|
|
107
|
+
*
|
|
108
|
+
* Flow:
|
|
109
|
+
* 1. Check rate limits (IP + email)
|
|
110
|
+
* 2. Look up account by email
|
|
111
|
+
* 3. Verify Argon2id hash
|
|
112
|
+
* 4. Check banned status
|
|
113
|
+
* 5. Create session
|
|
114
|
+
* 6. Return { sessionToken, userId }
|
|
115
|
+
*/
|
|
116
|
+
export const signIn = internalAction({
|
|
117
|
+
args: {
|
|
118
|
+
email: v.string(),
|
|
119
|
+
password: v.string(),
|
|
120
|
+
ipAddress: v.optional(v.string()),
|
|
121
|
+
userAgent: v.optional(v.string()),
|
|
122
|
+
requireEmailVerified: v.optional(v.boolean()),
|
|
123
|
+
},
|
|
124
|
+
handler: async (ctx, args) => {
|
|
125
|
+
const { email, password, ipAddress, userAgent, requireEmailVerified } = args;
|
|
126
|
+
const normalizedEmail = email.toLowerCase();
|
|
127
|
+
// 1. Check rate limits
|
|
128
|
+
const rateLimitKeys = [];
|
|
129
|
+
if (ipAddress)
|
|
130
|
+
rateLimitKeys.push(`signin:ip:${ipAddress}`);
|
|
131
|
+
rateLimitKeys.push(`signin:email:${normalizedEmail}`);
|
|
132
|
+
for (const key of rateLimitKeys) {
|
|
133
|
+
const rateCheck = await ctx.runQuery(internal.lib.rateLimit.check, {
|
|
134
|
+
key,
|
|
135
|
+
});
|
|
136
|
+
if (rateCheck.limited) {
|
|
137
|
+
throw new Error("Too many failed attempts. Please try again later.");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Helper to record failure
|
|
141
|
+
const recordFailure = async () => {
|
|
142
|
+
for (const key of rateLimitKeys) {
|
|
143
|
+
await ctx.runMutation(internal.lib.rateLimit.increment, { key });
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
// 2. Look up account by email
|
|
147
|
+
const account = await ctx.runQuery(internal.core.users.getAccount, {
|
|
148
|
+
providerId: "credential",
|
|
149
|
+
accountId: normalizedEmail,
|
|
150
|
+
});
|
|
151
|
+
if (!account || !account.passwordHash) {
|
|
152
|
+
await recordFailure();
|
|
153
|
+
throw new Error("Invalid email or password");
|
|
154
|
+
}
|
|
155
|
+
// 3. Verify Argon2id hash
|
|
156
|
+
const isValid = await argon2Verify({
|
|
157
|
+
password,
|
|
158
|
+
hash: account.passwordHash,
|
|
159
|
+
});
|
|
160
|
+
if (!isValid) {
|
|
161
|
+
await recordFailure();
|
|
162
|
+
throw new Error("Invalid email or password");
|
|
163
|
+
}
|
|
164
|
+
// 4. Check email verified if required
|
|
165
|
+
const user = await ctx.runQuery(internal.core.users.getById, {
|
|
166
|
+
userId: account.userId,
|
|
167
|
+
});
|
|
168
|
+
if (requireEmailVerified && !user?.emailVerified) {
|
|
169
|
+
throw new Error("Email address not verified");
|
|
170
|
+
}
|
|
171
|
+
// 4b. Check banned status
|
|
172
|
+
if (user?.banned) {
|
|
173
|
+
const now = Date.now();
|
|
174
|
+
if (user.banExpires === undefined || user.banExpires > now) {
|
|
175
|
+
throw new Error(`Account banned${user.banReason ? ": " + user.banReason : ""}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// 5. Reset rate limits on success
|
|
179
|
+
for (const key of rateLimitKeys) {
|
|
180
|
+
await ctx.runMutation(internal.lib.rateLimit.reset, { key });
|
|
181
|
+
}
|
|
182
|
+
// 6. Create session
|
|
183
|
+
const sessionToken = await ctx.runMutation(internal.core.sessions.create, {
|
|
184
|
+
userId: account.userId,
|
|
185
|
+
ipAddress,
|
|
186
|
+
userAgent,
|
|
187
|
+
});
|
|
188
|
+
return { sessionToken, userId: account.userId };
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
/**
|
|
192
|
+
* Verify email address with a verification code.
|
|
193
|
+
*/
|
|
194
|
+
export const verifyEmail = internalAction({
|
|
195
|
+
args: {
|
|
196
|
+
email: v.string(),
|
|
197
|
+
code: v.string(),
|
|
198
|
+
},
|
|
199
|
+
handler: async (ctx, { email, code }) => {
|
|
200
|
+
const normalizedEmail = email.toLowerCase();
|
|
201
|
+
const result = await ctx.runMutation(internal.core.verifications.verify, {
|
|
202
|
+
identifier: normalizedEmail,
|
|
203
|
+
type: "email-verification",
|
|
204
|
+
code,
|
|
205
|
+
});
|
|
206
|
+
if (result.status !== "valid") {
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
// Mark user as verified
|
|
210
|
+
const user = await ctx.runQuery(internal.core.users.getByEmail, {
|
|
211
|
+
email: normalizedEmail,
|
|
212
|
+
});
|
|
213
|
+
if (user) {
|
|
214
|
+
await ctx.runMutation(internal.core.users.update, {
|
|
215
|
+
userId: user._id,
|
|
216
|
+
emailVerified: true,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return { status: "valid" };
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
/**
|
|
223
|
+
* Request a password reset code.
|
|
224
|
+
* Returns the reset code so the host app can send the email.
|
|
225
|
+
* Always returns { status: "sent" } to prevent email enumeration.
|
|
226
|
+
* Returns resetCode only when a real user was found.
|
|
227
|
+
*/
|
|
228
|
+
export const requestPasswordReset = internalAction({
|
|
229
|
+
args: {
|
|
230
|
+
email: v.string(),
|
|
231
|
+
ipAddress: v.optional(v.string()),
|
|
232
|
+
},
|
|
233
|
+
handler: async (ctx, args) => {
|
|
234
|
+
const { email, ipAddress } = args;
|
|
235
|
+
const normalizedEmail = email.toLowerCase();
|
|
236
|
+
// Rate limit
|
|
237
|
+
if (ipAddress) {
|
|
238
|
+
const key = `reset:ip:${ipAddress}`;
|
|
239
|
+
const rateCheck = await ctx.runQuery(internal.lib.rateLimit.check, {
|
|
240
|
+
key,
|
|
241
|
+
});
|
|
242
|
+
if (rateCheck.limited) {
|
|
243
|
+
// Don't reveal if email exists; return success silently
|
|
244
|
+
return { status: "sent", resetCode: null };
|
|
245
|
+
}
|
|
246
|
+
await ctx.runMutation(internal.lib.rateLimit.increment, { key });
|
|
247
|
+
}
|
|
248
|
+
const user = await ctx.runQuery(internal.core.users.getByEmail, {
|
|
249
|
+
email: normalizedEmail,
|
|
250
|
+
});
|
|
251
|
+
if (!user) {
|
|
252
|
+
// Always return success to prevent email enumeration
|
|
253
|
+
return { status: "sent", resetCode: null };
|
|
254
|
+
}
|
|
255
|
+
const { code, expiresAt } = await ctx.runMutation(internal.core.verifications.create, {
|
|
256
|
+
identifier: normalizedEmail,
|
|
257
|
+
type: "password-reset",
|
|
258
|
+
});
|
|
259
|
+
await ctx.scheduler.runAt(expiresAt, internal.core.verifications.cleanup, {});
|
|
260
|
+
return { status: "sent", resetCode: code };
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
/**
|
|
264
|
+
* Reset password using a verification code.
|
|
265
|
+
*/
|
|
266
|
+
export const resetPassword = internalAction({
|
|
267
|
+
args: {
|
|
268
|
+
email: v.string(),
|
|
269
|
+
code: v.string(),
|
|
270
|
+
newPassword: v.string(),
|
|
271
|
+
},
|
|
272
|
+
handler: async (ctx, { email, code, newPassword }) => {
|
|
273
|
+
const normalizedEmail = email.toLowerCase();
|
|
274
|
+
const result = await ctx.runMutation(internal.core.verifications.verify, {
|
|
275
|
+
identifier: normalizedEmail,
|
|
276
|
+
type: "password-reset",
|
|
277
|
+
code,
|
|
278
|
+
});
|
|
279
|
+
if (result.status !== "valid") {
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
// Hash new password
|
|
283
|
+
const passwordHash = await hashPassword(newPassword);
|
|
284
|
+
// Update account password hash
|
|
285
|
+
const account = await ctx.runQuery(internal.core.users.getAccount, {
|
|
286
|
+
providerId: "credential",
|
|
287
|
+
accountId: normalizedEmail,
|
|
288
|
+
});
|
|
289
|
+
if (!account) {
|
|
290
|
+
throw new Error("Account not found");
|
|
291
|
+
}
|
|
292
|
+
await ctx.runMutation(internal.providers.emailPassword.updatePasswordHash, {
|
|
293
|
+
accountId: account._id,
|
|
294
|
+
passwordHash,
|
|
295
|
+
});
|
|
296
|
+
// Invalidate all sessions (force re-login after password reset)
|
|
297
|
+
await ctx.runMutation(internal.core.sessions.invalidateAll, {
|
|
298
|
+
userId: account.userId,
|
|
299
|
+
});
|
|
300
|
+
return { status: "valid" };
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
/** Internal mutation to update password hash on an account. */
|
|
304
|
+
export const updatePasswordHash = internalMutation({
|
|
305
|
+
args: {
|
|
306
|
+
accountId: v.id("accounts"),
|
|
307
|
+
passwordHash: v.string(),
|
|
308
|
+
},
|
|
309
|
+
handler: async (ctx, { accountId, passwordHash }) => {
|
|
310
|
+
await ctx.db.patch(accountId, {
|
|
311
|
+
passwordHash,
|
|
312
|
+
updatedAt: Date.now(),
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
//# sourceMappingURL=emailPassword.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emailPassword.js","sourceRoot":"","sources":["../../../src/component/providers/emailPassword.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type GenericId } from "convex/values";
|
|
2
|
+
/** Store OAuth state and code verifier for PKCE flow. */
|
|
3
|
+
export declare const storeOAuthState: import("convex/server").RegisteredMutation<"internal", {
|
|
4
|
+
redirectUrl?: string;
|
|
5
|
+
expiresAt: number;
|
|
6
|
+
stateHash: string;
|
|
7
|
+
codeVerifier: string;
|
|
8
|
+
provider: string;
|
|
9
|
+
}, Promise<void>>;
|
|
10
|
+
/** Retrieve and delete an OAuth state record by state hash (single-use). */
|
|
11
|
+
export declare const consumeOAuthState: import("convex/server").RegisteredMutation<"internal", {
|
|
12
|
+
stateHash: string;
|
|
13
|
+
}, Promise<{
|
|
14
|
+
_id: GenericId<"oauthStates">;
|
|
15
|
+
_creationTime: number;
|
|
16
|
+
redirectUrl?: string;
|
|
17
|
+
createdAt: number;
|
|
18
|
+
expiresAt: number;
|
|
19
|
+
stateHash: string;
|
|
20
|
+
codeVerifier: string;
|
|
21
|
+
provider: string;
|
|
22
|
+
} | null>>;
|
|
23
|
+
/**
|
|
24
|
+
* Initiate an OAuth authorization flow.
|
|
25
|
+
* Returns the authorization URL with PKCE + state parameters.
|
|
26
|
+
*/
|
|
27
|
+
export declare const getAuthorizationUrl: any;
|
|
28
|
+
/**
|
|
29
|
+
* Handle the OAuth callback.
|
|
30
|
+
* Validates state, exchanges code for tokens, upserts user, creates session.
|
|
31
|
+
*/
|
|
32
|
+
export declare const handleCallback: any;
|
|
33
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../../src/component/providers/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAK,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AA6ClD,yDAAyD;AACzD,eAAO,MAAM,eAAe;;;;;;iBAmB1B,CAAC;AAEH,4EAA4E;AAC5E,eAAO,MAAM,iBAAiB;;;;;;;;;;;UAmB5B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,mBAAmB,KAyC9B,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc,KA6KzB,CAAC"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { v } from "convex/values";
|
|
2
|
+
import { internalAction, internalMutation } from "../_generated/server";
|
|
3
|
+
import { internal } from "../_generated/api";
|
|
4
|
+
import { generateState, generateCodeVerifier, generateCodeChallenge, hashToken, } from "../lib/crypto";
|
|
5
|
+
import { oauthProviderConfigValidator } from "../lib/validators";
|
|
6
|
+
/** OAuth state TTL: 10 minutes. */
|
|
7
|
+
const STATE_TTL_MS = 10 * 60 * 1000;
|
|
8
|
+
function assertValidProviderConfig(provider) {
|
|
9
|
+
const required = [
|
|
10
|
+
provider.id,
|
|
11
|
+
provider.clientId,
|
|
12
|
+
provider.clientSecret,
|
|
13
|
+
provider.authorizationUrl,
|
|
14
|
+
provider.tokenUrl,
|
|
15
|
+
provider.userInfoUrl,
|
|
16
|
+
];
|
|
17
|
+
if (required.some((value) => value.trim().length === 0)) {
|
|
18
|
+
throw new Error("Invalid OAuth provider configuration");
|
|
19
|
+
}
|
|
20
|
+
if (provider.scopes.length === 0) {
|
|
21
|
+
throw new Error("OAuth provider scopes must not be empty");
|
|
22
|
+
}
|
|
23
|
+
const urls = [provider.authorizationUrl, provider.tokenUrl, provider.userInfoUrl];
|
|
24
|
+
for (const rawUrl of urls) {
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
parsed = new URL(rawUrl);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new Error("Invalid OAuth provider URL");
|
|
31
|
+
}
|
|
32
|
+
if (parsed.protocol !== "https:") {
|
|
33
|
+
throw new Error("OAuth provider URLs must use HTTPS");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Store OAuth state and code verifier for PKCE flow. */
|
|
38
|
+
export const storeOAuthState = internalMutation({
|
|
39
|
+
args: {
|
|
40
|
+
stateHash: v.string(),
|
|
41
|
+
codeVerifier: v.string(),
|
|
42
|
+
provider: v.string(),
|
|
43
|
+
redirectUrl: v.optional(v.string()),
|
|
44
|
+
expiresAt: v.number(),
|
|
45
|
+
},
|
|
46
|
+
handler: async (ctx, args) => {
|
|
47
|
+
const now = Date.now();
|
|
48
|
+
await ctx.db.insert("oauthStates", {
|
|
49
|
+
stateHash: args.stateHash,
|
|
50
|
+
codeVerifier: args.codeVerifier,
|
|
51
|
+
provider: args.provider,
|
|
52
|
+
redirectUrl: args.redirectUrl,
|
|
53
|
+
expiresAt: args.expiresAt,
|
|
54
|
+
createdAt: now,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
/** Retrieve and delete an OAuth state record by state hash (single-use). */
|
|
59
|
+
export const consumeOAuthState = internalMutation({
|
|
60
|
+
args: { stateHash: v.string() },
|
|
61
|
+
handler: async (ctx, { stateHash }) => {
|
|
62
|
+
const record = await ctx.db
|
|
63
|
+
.query("oauthStates")
|
|
64
|
+
.withIndex("by_stateHash", (q) => q.eq("stateHash", stateHash))
|
|
65
|
+
.unique();
|
|
66
|
+
if (!record)
|
|
67
|
+
return null;
|
|
68
|
+
// Delete immediately (single-use)
|
|
69
|
+
await ctx.db.delete(record._id);
|
|
70
|
+
if (record.expiresAt < Date.now()) {
|
|
71
|
+
return null; // Expired
|
|
72
|
+
}
|
|
73
|
+
return record;
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Initiate an OAuth authorization flow.
|
|
78
|
+
* Returns the authorization URL with PKCE + state parameters.
|
|
79
|
+
*/
|
|
80
|
+
export const getAuthorizationUrl = internalAction({
|
|
81
|
+
args: {
|
|
82
|
+
provider: oauthProviderConfigValidator,
|
|
83
|
+
redirectUrl: v.optional(v.string()),
|
|
84
|
+
},
|
|
85
|
+
handler: async (ctx, args) => {
|
|
86
|
+
const provider = args.provider;
|
|
87
|
+
assertValidProviderConfig(provider);
|
|
88
|
+
// Generate state (32 bytes = 256 bit)
|
|
89
|
+
const state = generateState();
|
|
90
|
+
const stateHash = await hashToken(state);
|
|
91
|
+
// Generate PKCE code verifier and challenge
|
|
92
|
+
const codeVerifier = generateCodeVerifier();
|
|
93
|
+
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
94
|
+
const expiresAt = Date.now() + STATE_TTL_MS;
|
|
95
|
+
await ctx.runMutation(internal.providers.oauth.storeOAuthState, {
|
|
96
|
+
stateHash,
|
|
97
|
+
codeVerifier,
|
|
98
|
+
provider: provider.id,
|
|
99
|
+
redirectUrl: args.redirectUrl,
|
|
100
|
+
expiresAt,
|
|
101
|
+
});
|
|
102
|
+
// Build authorization URL
|
|
103
|
+
const url = new URL(provider.authorizationUrl);
|
|
104
|
+
url.searchParams.set("client_id", provider.clientId);
|
|
105
|
+
url.searchParams.set("response_type", "code");
|
|
106
|
+
url.searchParams.set("scope", provider.scopes.join(" "));
|
|
107
|
+
url.searchParams.set("state", state);
|
|
108
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
109
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
110
|
+
if (args.redirectUrl) {
|
|
111
|
+
url.searchParams.set("redirect_uri", args.redirectUrl);
|
|
112
|
+
}
|
|
113
|
+
return { authorizationUrl: url.toString() };
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
/**
|
|
117
|
+
* Handle the OAuth callback.
|
|
118
|
+
* Validates state, exchanges code for tokens, upserts user, creates session.
|
|
119
|
+
*/
|
|
120
|
+
export const handleCallback = internalAction({
|
|
121
|
+
args: {
|
|
122
|
+
provider: oauthProviderConfigValidator,
|
|
123
|
+
code: v.string(),
|
|
124
|
+
state: v.string(),
|
|
125
|
+
redirectUrl: v.optional(v.string()),
|
|
126
|
+
ipAddress: v.optional(v.string()),
|
|
127
|
+
userAgent: v.optional(v.string()),
|
|
128
|
+
},
|
|
129
|
+
handler: async (ctx, args) => {
|
|
130
|
+
const provider = args.provider;
|
|
131
|
+
assertValidProviderConfig(provider);
|
|
132
|
+
// Use global fetch; tests can mock it via vi.spyOn(globalThis, 'fetch')
|
|
133
|
+
const fetchFn = fetch;
|
|
134
|
+
// 1. Validate state against stored stateHash
|
|
135
|
+
const stateHash = await hashToken(args.state);
|
|
136
|
+
const stateRecord = await ctx.runMutation(internal.providers.oauth.consumeOAuthState, { stateHash });
|
|
137
|
+
if (!stateRecord) {
|
|
138
|
+
throw new Error("Invalid or expired OAuth state");
|
|
139
|
+
}
|
|
140
|
+
if (stateRecord.provider !== provider.id) {
|
|
141
|
+
throw new Error("Provider mismatch in OAuth state");
|
|
142
|
+
}
|
|
143
|
+
// 2. Exchange code + code_verifier for tokens
|
|
144
|
+
const tokenParams = new URLSearchParams({
|
|
145
|
+
grant_type: "authorization_code",
|
|
146
|
+
client_id: provider.clientId,
|
|
147
|
+
client_secret: provider.clientSecret,
|
|
148
|
+
code: args.code,
|
|
149
|
+
code_verifier: stateRecord.codeVerifier,
|
|
150
|
+
});
|
|
151
|
+
if (args.redirectUrl ?? stateRecord.redirectUrl) {
|
|
152
|
+
tokenParams.set("redirect_uri", (args.redirectUrl ?? stateRecord.redirectUrl));
|
|
153
|
+
}
|
|
154
|
+
const tokenRes = await fetchFn(provider.tokenUrl, {
|
|
155
|
+
method: "POST",
|
|
156
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
157
|
+
body: tokenParams.toString(),
|
|
158
|
+
});
|
|
159
|
+
if (!tokenRes.ok) {
|
|
160
|
+
throw new Error(`Token exchange failed: ${tokenRes.status}`);
|
|
161
|
+
}
|
|
162
|
+
const tokens = await tokenRes.json();
|
|
163
|
+
// 3. Fetch user profile from provider
|
|
164
|
+
const userRes = await fetchFn(provider.userInfoUrl, {
|
|
165
|
+
headers: { Authorization: `Bearer ${tokens.access_token}` },
|
|
166
|
+
});
|
|
167
|
+
if (!userRes.ok) {
|
|
168
|
+
throw new Error(`User info fetch failed: ${userRes.status}`);
|
|
169
|
+
}
|
|
170
|
+
const profile = await userRes.json();
|
|
171
|
+
const providerId = provider.id;
|
|
172
|
+
const accountId = (profile.id ?? profile.sub)?.toString();
|
|
173
|
+
if (!accountId) {
|
|
174
|
+
throw new Error("Could not determine provider user ID");
|
|
175
|
+
}
|
|
176
|
+
const email = profile.email?.toLowerCase();
|
|
177
|
+
const name = profile.name ?? profile.login;
|
|
178
|
+
const image = profile.picture ?? profile.avatar_url;
|
|
179
|
+
const accessTokenExpiresAt = tokens.expires_in
|
|
180
|
+
? Date.now() + tokens.expires_in * 1000
|
|
181
|
+
: undefined;
|
|
182
|
+
// 4. Find existing account or create user + account (account linking by email)
|
|
183
|
+
const existingAccount = await ctx.runQuery(internal.core.users.getAccount, {
|
|
184
|
+
providerId,
|
|
185
|
+
accountId,
|
|
186
|
+
});
|
|
187
|
+
let userId;
|
|
188
|
+
if (existingAccount) {
|
|
189
|
+
// Update tokens on existing account
|
|
190
|
+
await ctx.runMutation(internal.core.users.updateAccount, {
|
|
191
|
+
accountId: existingAccount._id,
|
|
192
|
+
accessToken: tokens.access_token,
|
|
193
|
+
refreshToken: tokens.refresh_token,
|
|
194
|
+
accessTokenExpiresAt,
|
|
195
|
+
});
|
|
196
|
+
userId = existingAccount.userId;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// Try to link by email
|
|
200
|
+
const existingUser = email
|
|
201
|
+
? await ctx.runQuery(internal.core.users.getByEmail, { email })
|
|
202
|
+
: null;
|
|
203
|
+
if (!existingUser && email) {
|
|
204
|
+
// Create new user
|
|
205
|
+
userId = await ctx.runMutation(internal.core.users.create, {
|
|
206
|
+
email,
|
|
207
|
+
emailVerified: true, // OAuth providers verify email
|
|
208
|
+
name,
|
|
209
|
+
image,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
else if (existingUser) {
|
|
213
|
+
userId = existingUser._id;
|
|
214
|
+
// Update profile info from OAuth
|
|
215
|
+
await ctx.runMutation(internal.core.users.update, {
|
|
216
|
+
userId: existingUser._id,
|
|
217
|
+
emailVerified: true,
|
|
218
|
+
name: name ?? existingUser.name,
|
|
219
|
+
image: image ?? existingUser.image,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
throw new Error("OAuth provider did not return an email address");
|
|
224
|
+
}
|
|
225
|
+
// Create account entry
|
|
226
|
+
await ctx.runMutation(internal.core.users.createAccount, {
|
|
227
|
+
userId,
|
|
228
|
+
providerId,
|
|
229
|
+
accountId,
|
|
230
|
+
accessToken: tokens.access_token,
|
|
231
|
+
refreshToken: tokens.refresh_token,
|
|
232
|
+
accessTokenExpiresAt,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
// 5. Check banned status
|
|
236
|
+
const user = await ctx.runQuery(internal.core.users.getById, { userId });
|
|
237
|
+
if (user?.banned) {
|
|
238
|
+
const now = Date.now();
|
|
239
|
+
if (user.banExpires === undefined || user.banExpires > now) {
|
|
240
|
+
throw new Error(`Account banned${user.banReason ? ": " + user.banReason : ""}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
// 6. Create session
|
|
244
|
+
const sessionToken = await ctx.runMutation(internal.core.sessions.create, {
|
|
245
|
+
userId,
|
|
246
|
+
ipAddress: args.ipAddress,
|
|
247
|
+
userAgent: args.userAgent,
|
|
248
|
+
});
|
|
249
|
+
return {
|
|
250
|
+
sessionToken,
|
|
251
|
+
userId,
|
|
252
|
+
redirectUrl: stateRecord.redirectUrl,
|
|
253
|
+
};
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../../src/component/providers/oauth.ts"],"names":[],"mappings":"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"}
|