From 573528be41ce22c34609dcd99b28cfd2f66b34d7 Mon Sep 17 00:00:00 2001 From: liuyi Date: Wed, 13 Mar 2024 07:50:10 +0000 Subject: [PATCH] fix(server): user can not signup through oauth if ever invited (#6101) --- .../migration.sql | 2 ++ packages/backend/server/schema.prisma | 3 +++ .../server/src/core/auth/controller.ts | 3 ++- .../server/src/core/auth/current-user.ts | 2 +- .../backend/server/src/core/auth/service.ts | 16 +++++++++---- .../server/src/core/user/management.ts | 4 +++- .../backend/server/src/core/user/service.ts | 23 ++++++++++++++++++- .../core/workspaces/resolvers/workspace.ts | 4 +++- .../server/src/plugins/oauth/controller.ts | 14 ++++++++--- 9 files changed, 58 insertions(+), 13 deletions(-) create mode 100644 packages/backend/server/migrations/20240313033631_user_registered_flag/migration.sql diff --git a/packages/backend/server/migrations/20240313033631_user_registered_flag/migration.sql b/packages/backend/server/migrations/20240313033631_user_registered_flag/migration.sql new file mode 100644 index 0000000000..aba95ca449 --- /dev/null +++ b/packages/backend/server/migrations/20240313033631_user_registered_flag/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "users" ADD COLUMN "registered" BOOLEAN NOT NULL DEFAULT true; diff --git a/packages/backend/server/schema.prisma b/packages/backend/server/schema.prisma index df67e2dfc6..508f4052c5 100644 --- a/packages/backend/server/schema.prisma +++ b/packages/backend/server/schema.prisma @@ -18,6 +18,9 @@ model User { createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6) /// Not available if user signed up through OAuth providers password String? @db.VarChar + /// Indicate whether the user finished the signup progress. + /// for example, the value will be false if user never registered and invited into a workspace by others. + registered Boolean @default(true) features UserFeatures[] customer UserStripeCustomer? diff --git a/packages/backend/server/src/core/auth/controller.ts b/packages/backend/server/src/core/auth/controller.ts index ccad6b1008..e2ffed2525 100644 --- a/packages/backend/server/src/core/auth/controller.ts +++ b/packages/backend/server/src/core/auth/controller.ts @@ -152,8 +152,9 @@ export class AuthController { throw new BadRequestException('Invalid Sign-in mail Token'); } - const user = await this.user.findOrCreateUser(email, { + const user = await this.user.fulfillUser(email, { emailVerifiedAt: new Date(), + registered: true, }); await this.auth.setCookie(req, res, user); diff --git a/packages/backend/server/src/core/auth/current-user.ts b/packages/backend/server/src/core/auth/current-user.ts index 1aaa5b59cd..b6757314f1 100644 --- a/packages/backend/server/src/core/auth/current-user.ts +++ b/packages/backend/server/src/core/auth/current-user.ts @@ -49,7 +49,7 @@ export const CurrentUser = createParamDecorator( ); export interface CurrentUser - extends Omit { + extends Pick { hasPassword: boolean | null; emailVerified: boolean; } diff --git a/packages/backend/server/src/core/auth/service.ts b/packages/backend/server/src/core/auth/service.ts index e568937b56..187f3b28cd 100644 --- a/packages/backend/server/src/core/auth/service.ts +++ b/packages/backend/server/src/core/auth/service.ts @@ -36,12 +36,18 @@ export function parseAuthUserSeqNum(value: any) { } export function sessionUser( - user: Omit & { password?: string | null } + user: Pick< + User, + 'id' | 'email' | 'avatarUrl' | 'name' | 'emailVerifiedAt' + > & { password?: string | null } ): CurrentUser { - return assign(omit(user, 'password', 'emailVerifiedAt', 'createdAt'), { - hasPassword: user.password !== null, - emailVerified: user.emailVerifiedAt !== null, - }); + return assign( + omit(user, 'password', 'registered', 'emailVerifiedAt', 'createdAt'), + { + hasPassword: user.password !== null, + emailVerified: user.emailVerifiedAt !== null, + } + ); } @Injectable() diff --git a/packages/backend/server/src/core/user/management.ts b/packages/backend/server/src/core/user/management.ts index 8cc158b6e3..af6f740f29 100644 --- a/packages/backend/server/src/core/user/management.ts +++ b/packages/backend/server/src/core/user/management.ts @@ -42,7 +42,9 @@ export class UserManagementResolver { if (user) { return this.feature.addEarlyAccess(user.id); } else { - const user = await this.users.createAnonymousUser(email); + const user = await this.users.createAnonymousUser(email, { + registered: false, + }); return this.feature.addEarlyAccess(user.id); } } diff --git a/packages/backend/server/src/core/user/service.ts b/packages/backend/server/src/core/user/service.ts index aaf91ef79f..4c60f00975 100644 --- a/packages/backend/server/src/core/user/service.ts +++ b/packages/backend/server/src/core/user/service.ts @@ -11,11 +11,12 @@ export class UserService { email: true, emailVerifiedAt: true, avatarUrl: true, + registered: true, } satisfies Prisma.UserSelect; constructor(private readonly prisma: PrismaClient) {} - get userCreatingData(): Partial { + get userCreatingData() { return { name: 'Unnamed', features: { @@ -106,6 +107,26 @@ export class UserService { return this.createAnonymousUser(email, data); } + async fulfillUser( + email: string, + data: Partial< + Pick + > + ) { + return this.prisma.user.upsert({ + select: this.defaultUserSelect, + where: { + email, + }, + update: data, + create: { + email, + ...this.userCreatingData, + ...data, + }, + }); + } + async deleteUser(id: string) { return this.prisma.user.delete({ where: { id } }); } diff --git a/packages/backend/server/src/core/workspaces/resolvers/workspace.ts b/packages/backend/server/src/core/workspaces/resolvers/workspace.ts index 206a7598da..d322a69c1b 100644 --- a/packages/backend/server/src/core/workspaces/resolvers/workspace.ts +++ b/packages/backend/server/src/core/workspaces/resolvers/workspace.ts @@ -358,7 +358,9 @@ export class WorkspaceResolver { // only invite if the user is not already in the workspace if (originRecord) return originRecord.id; } else { - target = await this.users.createAnonymousUser(email); + target = await this.users.createAnonymousUser(email, { + registered: false, + }); } const inviteId = await this.permissions.grant( diff --git a/packages/backend/server/src/plugins/oauth/controller.ts b/packages/backend/server/src/plugins/oauth/controller.ts index 92f968e892..29c17c78a1 100644 --- a/packages/backend/server/src/plugins/oauth/controller.ts +++ b/packages/backend/server/src/plugins/oauth/controller.ts @@ -153,9 +153,17 @@ export class OAuthController { if (user) { // we can't directly connect the external account with given email in sign in scenario for safety concern. // let user manually connect in account sessions instead. - throw new BadRequestException( - 'The account with provided email is not register in the same way.' - ); + if (user.registered) { + throw new BadRequestException( + 'The account with provided email is not register in the same way.' + ); + } + + await this.user.fulfillUser(externalAccount.email, { + registered: true, + }); + + return user; } else { user = await this.createUserWithConnectedAccount( provider,