mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-11 23:26:30 +08:00
@@ -1,4 +1,5 @@
|
||||
import { AIProvider } from '@affine/core/blocksuite/presets/ai';
|
||||
import { buildAppUrl, popupWindow } from '@affine/core/utils';
|
||||
import { apis, appInfo } from '@affine/electron-api';
|
||||
import type { OAuthProviderType } from '@affine/graphql';
|
||||
import {
|
||||
@@ -80,72 +81,82 @@ export class AuthService extends Service {
|
||||
async sendEmailMagicLink(
|
||||
email: string,
|
||||
verifyToken: string,
|
||||
challenge?: string,
|
||||
redirectUri?: string | null
|
||||
challenge?: string
|
||||
) {
|
||||
const searchParams = new URLSearchParams();
|
||||
if (challenge) {
|
||||
searchParams.set('challenge', challenge);
|
||||
}
|
||||
searchParams.set('token', verifyToken);
|
||||
const redirect = environment.isDesktop
|
||||
? this.buildRedirectUri('/open-app/signin-redirect')
|
||||
: (redirectUri ?? location.href);
|
||||
searchParams.set('redirect_uri', redirect.toString());
|
||||
|
||||
const res = await this.fetchService.fetch(
|
||||
'/api/auth/sign-in?' + searchParams.toString(),
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ email }),
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
// we call it [callbackUrl] instead of [redirect_uri]
|
||||
// to make it clear the url is used to finish the sign-in process instead of redirect after signed-in
|
||||
callbackUrl: buildAppUrl('/magic-link', {
|
||||
desktop: environment.isDesktop,
|
||||
openInHiddenWindow: true,
|
||||
redirectFromWeb: true,
|
||||
}),
|
||||
}),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
if (!res?.ok) {
|
||||
if (!res.ok) {
|
||||
throw new Error('Failed to send email');
|
||||
}
|
||||
}
|
||||
|
||||
async signInOauth(provider: OAuthProviderType, redirectUri?: string | null) {
|
||||
async signInOauth(provider: OAuthProviderType) {
|
||||
const res = await this.fetchService.fetch('/api/oauth/preflight', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ provider }),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to sign in with ${provider}`);
|
||||
}
|
||||
|
||||
let { url } = await res.json();
|
||||
|
||||
// change `state=xxx` to `state={state:xxx,native:true}`
|
||||
// so we could know the callback should be redirect to native app
|
||||
const oauthUrl = new URL(url);
|
||||
oauthUrl.searchParams.set(
|
||||
'state',
|
||||
JSON.stringify({
|
||||
state: oauthUrl.searchParams.get('state'),
|
||||
client: environment.isDesktop ? appInfo?.schema : 'web',
|
||||
})
|
||||
);
|
||||
url = oauthUrl.toString();
|
||||
|
||||
if (environment.isDesktop) {
|
||||
await apis?.ui.openExternal(
|
||||
`${
|
||||
runtimeConfig.serverUrlPrefix
|
||||
}/desktop-signin?provider=${provider}&redirect_uri=${this.buildRedirectUri(
|
||||
'/open-app/signin-redirect'
|
||||
)}`
|
||||
);
|
||||
await apis?.ui.openExternal(url);
|
||||
} else {
|
||||
location.href = `${
|
||||
runtimeConfig.serverUrlPrefix
|
||||
}/oauth/login?provider=${provider}&redirect_uri=${encodeURIComponent(
|
||||
redirectUri ?? location.pathname
|
||||
)}`;
|
||||
popupWindow(url);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async signInPassword(credential: { email: string; password: string }) {
|
||||
const searchParams = new URLSearchParams();
|
||||
const redirectUri = new URL(location.href);
|
||||
if (environment.isDesktop) {
|
||||
redirectUri.pathname = this.buildRedirectUri('/open-app/signin-redirect');
|
||||
}
|
||||
searchParams.set('redirect_uri', redirectUri.toString());
|
||||
|
||||
const res = await this.fetchService.fetch(
|
||||
'/api/auth/sign-in?' + searchParams.toString(),
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(credential),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
}
|
||||
);
|
||||
const res = await this.fetchService.fetch('/api/auth/sign-in', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(credential),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
});
|
||||
if (!res.ok) {
|
||||
throw new Error('Failed to sign in');
|
||||
}
|
||||
@@ -158,19 +169,6 @@ export class AuthService extends Service {
|
||||
this.session.revalidate();
|
||||
}
|
||||
|
||||
private buildRedirectUri(callbackUrl: string) {
|
||||
const params: string[][] = [];
|
||||
if (environment.isDesktop && appInfo?.schema) {
|
||||
params.push(['schema', appInfo.schema]);
|
||||
}
|
||||
const query =
|
||||
params.length > 0
|
||||
? '?' +
|
||||
params.map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&')
|
||||
: '';
|
||||
return callbackUrl + query;
|
||||
}
|
||||
|
||||
checkUserByEmail(email: string) {
|
||||
return this.store.checkUserByEmail(email);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
getUserQuery,
|
||||
removeAvatarMutation,
|
||||
updateUserProfileMutation,
|
||||
uploadAvatarMutation,
|
||||
@@ -81,15 +80,23 @@ export class AuthStore extends Store {
|
||||
}
|
||||
|
||||
async checkUserByEmail(email: string) {
|
||||
const data = await this.gqlService.gql({
|
||||
query: getUserQuery,
|
||||
variables: {
|
||||
email,
|
||||
const res = await this.fetchService.fetch('/api/auth/preflight', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ email }),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
});
|
||||
return {
|
||||
isExist: !!data.user,
|
||||
hasPassword: !!data.user?.hasPassword,
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to check user by email: ${email}`);
|
||||
}
|
||||
|
||||
const data = (await res.json()) as {
|
||||
registered: boolean;
|
||||
hasPassword: boolean;
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user