From 0e6a3467f07cb3f87ae256adb4137b446cb1e9b4 Mon Sep 17 00:00:00 2001 From: ABCxFF <79597906+ABCxFF@users.noreply.github.com> Date: Wed, 8 May 2024 12:15:39 -0400 Subject: [PATCH 1/4] feat(auth/tests): e2e verifying correct user ids --- modules/auth/tests/e2e.ts | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/modules/auth/tests/e2e.ts b/modules/auth/tests/e2e.ts index d56b32e0..9770db59 100644 --- a/modules/auth/tests/e2e.ts +++ b/modules/auth/tests/e2e.ts @@ -20,3 +20,37 @@ test("e2e", async (ctx: TestContext) => { }); assertEquals(verifyRes.token.type, "user"); }); + + +test("e2e with user token", async (ctx: TestContext) => { + const { user } = await ctx.modules.users.createUser({}); + + const { token: session } = await ctx.modules.users.createUserToken({ + userId: user.id + }); + + const authRes = await ctx.modules.auth.authEmailPasswordless({ + email: faker.internet.email(), + userToken: session.token + }); + + // Look up correct code + const { code } = await ctx.db.emailPasswordlessVerification.findFirstOrThrow({ + where: { + id: authRes.verification.id, + }, + }); + + const verifyRes = await ctx.modules.auth.verifyEmailPasswordless({ + verificationId: authRes.verification.id, + code: code, + }); + + assertEquals(verifyRes.token.type, "user"); + + const verifyRes2 = await ctx.modules.users.authenticateUser({ + userToken: verifyRes.token.token + }); + + assertEquals(verifyRes2.userId, user.id); +}); From 8150c85c80370e4072fec360a5efc145a06b4edd Mon Sep 17 00:00:00 2001 From: ABCxFF <79597906+ABCxFF@users.noreply.github.com> Date: Wed, 8 May 2024 12:18:29 -0400 Subject: [PATCH 2/4] fix(auth/auth_email_passwordless): properly finish fetch user code --- modules/auth/scripts/auth_email_passwordless.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/auth/scripts/auth_email_passwordless.ts b/modules/auth/scripts/auth_email_passwordless.ts index 217f320a..02b99938 100644 --- a/modules/auth/scripts/auth_email_passwordless.ts +++ b/modules/auth/scripts/auth_email_passwordless.ts @@ -22,7 +22,7 @@ export async function run( // Fetch existing user if session token is provided let userId: string | undefined; if (req.userToken) { - const { userId } = await ctx.modules.users.authenticateUser({ + const authRes = await ctx.modules.users.authenticateUser({ userToken: req.userToken, }); @@ -30,9 +30,12 @@ export async function run( const existingIdentity = await ctx.db.emailPasswordless.findFirst({ where: { email: req.email }, }); - if (existingIdentity && existingIdentity.userId !== userId) { + + if (existingIdentity && existingIdentity.userId !== authRes.userId) { throw new RuntimeError("email_already_used"); } + + userId = authRes.userId; } // Create verification From 6f96c0133d9b8a6825395d1169309fed3664ec60 Mon Sep 17 00:00:00 2001 From: ABCxFF <79597906+ABCxFF@users.noreply.github.com> Date: Mon, 20 May 2024 10:20:04 -0400 Subject: [PATCH 3/4] fix(auth with email): allow users to login with email but no token --- modules/auth/scripts/auth_email_passwordless.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/auth/scripts/auth_email_passwordless.ts b/modules/auth/scripts/auth_email_passwordless.ts index 02b99938..801f91d0 100644 --- a/modules/auth/scripts/auth_email_passwordless.ts +++ b/modules/auth/scripts/auth_email_passwordless.ts @@ -19,18 +19,19 @@ export async function run( if (!ctx.userConfig.email) throw new RuntimeError("provider_disabled"); + // Check if the email is already associated with an identity + const existingIdentity = await ctx.db.emailPasswordless.findFirst({ + where: { email: req.email }, + }); + // Fetch existing user if session token is provided - let userId: string | undefined; + let userId: string | undefined = existingIdentity?.userId; + if (req.userToken) { const authRes = await ctx.modules.users.authenticateUser({ userToken: req.userToken, }); - // Check if the email is already associated with an identity - const existingIdentity = await ctx.db.emailPasswordless.findFirst({ - where: { email: req.email }, - }); - if (existingIdentity && existingIdentity.userId !== authRes.userId) { throw new RuntimeError("email_already_used"); } From b228437bbb88e7bbd6a07431705394156de1a05f Mon Sep 17 00:00:00 2001 From: ABCxFF <79597906+ABCxFF@users.noreply.github.com> Date: Mon, 20 May 2024 10:32:34 -0400 Subject: [PATCH 4/4] chore: tests for #85 --- modules/auth/tests/e2e.ts | 95 +++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 38 deletions(-) diff --git a/modules/auth/tests/e2e.ts b/modules/auth/tests/e2e.ts index 9770db59..6d66eca0 100644 --- a/modules/auth/tests/e2e.ts +++ b/modules/auth/tests/e2e.ts @@ -3,54 +3,73 @@ import { assertEquals } from "https://deno.land/std@0.208.0/assert/mod.ts"; import { faker } from "https://deno.land/x/deno_faker@v1.0.3/mod.ts"; test("e2e", async (ctx: TestContext) => { - const authRes = await ctx.modules.auth.authEmailPasswordless({ - email: faker.internet.email(), - }); + // First we create a new user, and "register" into the auth + // using an authEmailPasswordless({ email, userToken }) + // call + const { user } = await ctx.modules.users.createUser({}); - // Look up correct code - const { code } = await ctx.db.emailPasswordlessVerification.findFirstOrThrow({ - where: { - id: authRes.verification.id, - }, + const { token: session } = await ctx.modules.users.createUserToken({ + userId: user.id }); - const verifyRes = await ctx.modules.auth.verifyEmailPasswordless({ - verificationId: authRes.verification.id, - code: code, - }); - assertEquals(verifyRes.token.type, "user"); -}); + const fakeEmail = faker.internet.email(); + // Now we test that post-signin, we get the same user + { + const authRes = await ctx.modules.auth.authEmailPasswordless({ + email: fakeEmail, + userToken: session.token + }); -test("e2e with user token", async (ctx: TestContext) => { - const { user } = await ctx.modules.users.createUser({}); + // Look up correct code + const { code } = await ctx.db.emailPasswordlessVerification.findFirstOrThrow({ + where: { + id: authRes.verification.id, + }, + }); - const { token: session } = await ctx.modules.users.createUserToken({ - userId: user.id - }); + // Now by verifying the email, we register, and can also use + // this to verify the token + const verifyRes = await ctx.modules.auth.verifyEmailPasswordless({ + verificationId: authRes.verification.id, + code: code, + }); - const authRes = await ctx.modules.auth.authEmailPasswordless({ - email: faker.internet.email(), - userToken: session.token - }); + assertEquals(verifyRes.token.type, "user"); - // Look up correct code - const { code } = await ctx.db.emailPasswordlessVerification.findFirstOrThrow({ - where: { - id: authRes.verification.id, - }, - }); - const verifyRes = await ctx.modules.auth.verifyEmailPasswordless({ - verificationId: authRes.verification.id, - code: code, - }); + // Make sure we end up with the same user we started with + const verifyRes2 = await ctx.modules.users.authenticateUser({ + userToken: verifyRes.token.token + }); - assertEquals(verifyRes.token.type, "user"); + assertEquals(verifyRes2.userId, user.id); + } - const verifyRes2 = await ctx.modules.users.authenticateUser({ - userToken: verifyRes.token.token - }); + // Now we try logging back in with the same email, + // but without a token, expecting the same user + { + const authRes = await ctx.modules.auth.authEmailPasswordless({ + email: fakeEmail + }); - assertEquals(verifyRes2.userId, user.id); + // Look up correct code + const { code: code } = await ctx.db.emailPasswordlessVerification.findFirstOrThrow({ + where: { + id: authRes.verification.id, + }, + }); + + const verifyRes = await ctx.modules.auth.verifyEmailPasswordless({ + verificationId: authRes.verification.id, + code: code, + }); + + const verifyRes2 = await ctx.modules.users.authenticateUser({ + userToken: verifyRes.token.token + }); + + assertEquals(verifyRes2.userId, user.id); + } }); +