mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-27 19:02:23 +08:00
fix(server): user can not signup through oauth if ever invited (#6101)
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "users" ADD COLUMN "registered" BOOLEAN NOT NULL DEFAULT true;
|
||||||
@@ -18,6 +18,9 @@ model User {
|
|||||||
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
||||||
/// Not available if user signed up through OAuth providers
|
/// Not available if user signed up through OAuth providers
|
||||||
password String? @db.VarChar
|
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[]
|
features UserFeatures[]
|
||||||
customer UserStripeCustomer?
|
customer UserStripeCustomer?
|
||||||
|
|||||||
@@ -152,8 +152,9 @@ export class AuthController {
|
|||||||
throw new BadRequestException('Invalid Sign-in mail Token');
|
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(),
|
emailVerifiedAt: new Date(),
|
||||||
|
registered: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.auth.setCookie(req, res, user);
|
await this.auth.setCookie(req, res, user);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export const CurrentUser = createParamDecorator(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export interface CurrentUser
|
export interface CurrentUser
|
||||||
extends Omit<User, 'password' | 'createdAt' | 'emailVerifiedAt'> {
|
extends Pick<User, 'id' | 'email' | 'avatarUrl' | 'name'> {
|
||||||
hasPassword: boolean | null;
|
hasPassword: boolean | null;
|
||||||
emailVerified: boolean;
|
emailVerified: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,12 +36,18 @@ export function parseAuthUserSeqNum(value: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function sessionUser(
|
export function sessionUser(
|
||||||
user: Omit<User, 'password'> & { password?: string | null }
|
user: Pick<
|
||||||
|
User,
|
||||||
|
'id' | 'email' | 'avatarUrl' | 'name' | 'emailVerifiedAt'
|
||||||
|
> & { password?: string | null }
|
||||||
): CurrentUser {
|
): CurrentUser {
|
||||||
return assign(omit(user, 'password', 'emailVerifiedAt', 'createdAt'), {
|
return assign(
|
||||||
hasPassword: user.password !== null,
|
omit(user, 'password', 'registered', 'emailVerifiedAt', 'createdAt'),
|
||||||
emailVerified: user.emailVerifiedAt !== null,
|
{
|
||||||
});
|
hasPassword: user.password !== null,
|
||||||
|
emailVerified: user.emailVerifiedAt !== null,
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ export class UserManagementResolver {
|
|||||||
if (user) {
|
if (user) {
|
||||||
return this.feature.addEarlyAccess(user.id);
|
return this.feature.addEarlyAccess(user.id);
|
||||||
} else {
|
} else {
|
||||||
const user = await this.users.createAnonymousUser(email);
|
const user = await this.users.createAnonymousUser(email, {
|
||||||
|
registered: false,
|
||||||
|
});
|
||||||
return this.feature.addEarlyAccess(user.id);
|
return this.feature.addEarlyAccess(user.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ export class UserService {
|
|||||||
email: true,
|
email: true,
|
||||||
emailVerifiedAt: true,
|
emailVerifiedAt: true,
|
||||||
avatarUrl: true,
|
avatarUrl: true,
|
||||||
|
registered: true,
|
||||||
} satisfies Prisma.UserSelect;
|
} satisfies Prisma.UserSelect;
|
||||||
|
|
||||||
constructor(private readonly prisma: PrismaClient) {}
|
constructor(private readonly prisma: PrismaClient) {}
|
||||||
|
|
||||||
get userCreatingData(): Partial<Prisma.UserCreateInput> {
|
get userCreatingData() {
|
||||||
return {
|
return {
|
||||||
name: 'Unnamed',
|
name: 'Unnamed',
|
||||||
features: {
|
features: {
|
||||||
@@ -106,6 +107,26 @@ export class UserService {
|
|||||||
return this.createAnonymousUser(email, data);
|
return this.createAnonymousUser(email, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fulfillUser(
|
||||||
|
email: string,
|
||||||
|
data: Partial<
|
||||||
|
Pick<Prisma.UserCreateInput, 'emailVerifiedAt' | 'registered'>
|
||||||
|
>
|
||||||
|
) {
|
||||||
|
return this.prisma.user.upsert({
|
||||||
|
select: this.defaultUserSelect,
|
||||||
|
where: {
|
||||||
|
email,
|
||||||
|
},
|
||||||
|
update: data,
|
||||||
|
create: {
|
||||||
|
email,
|
||||||
|
...this.userCreatingData,
|
||||||
|
...data,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async deleteUser(id: string) {
|
async deleteUser(id: string) {
|
||||||
return this.prisma.user.delete({ where: { id } });
|
return this.prisma.user.delete({ where: { id } });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -358,7 +358,9 @@ export class WorkspaceResolver {
|
|||||||
// only invite if the user is not already in the workspace
|
// only invite if the user is not already in the workspace
|
||||||
if (originRecord) return originRecord.id;
|
if (originRecord) return originRecord.id;
|
||||||
} else {
|
} else {
|
||||||
target = await this.users.createAnonymousUser(email);
|
target = await this.users.createAnonymousUser(email, {
|
||||||
|
registered: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const inviteId = await this.permissions.grant(
|
const inviteId = await this.permissions.grant(
|
||||||
|
|||||||
@@ -153,9 +153,17 @@ export class OAuthController {
|
|||||||
if (user) {
|
if (user) {
|
||||||
// we can't directly connect the external account with given email in sign in scenario for safety concern.
|
// 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.
|
// let user manually connect in account sessions instead.
|
||||||
throw new BadRequestException(
|
if (user.registered) {
|
||||||
'The account with provided email is not register in the same way.'
|
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 {
|
} else {
|
||||||
user = await this.createUserWithConnectedAccount(
|
user = await this.createUserWithConnectedAccount(
|
||||||
provider,
|
provider,
|
||||||
|
|||||||
Reference in New Issue
Block a user