mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-17 18:16:15 +08:00
feat(core): support apple sign in (#12424)
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
OauthAccountAlreadyConnected,
|
||||
OauthStateExpired,
|
||||
UnknownOauthProvider,
|
||||
URLHelper,
|
||||
UseNamedGuard,
|
||||
} from '../../base';
|
||||
import { AuthService, Public } from '../../core/auth';
|
||||
@@ -36,7 +37,8 @@ export class OAuthController {
|
||||
private readonly auth: AuthService,
|
||||
private readonly oauth: OAuthService,
|
||||
private readonly models: Models,
|
||||
private readonly providerFactory: OAuthProviderFactory
|
||||
private readonly providerFactory: OAuthProviderFactory,
|
||||
private readonly url: URLHelper
|
||||
) {}
|
||||
|
||||
@Public()
|
||||
@@ -67,10 +69,14 @@ export class OAuthController {
|
||||
clientNonce,
|
||||
});
|
||||
|
||||
const stateStr = JSON.stringify({
|
||||
state,
|
||||
client,
|
||||
provider: unknownProviderName,
|
||||
});
|
||||
|
||||
return {
|
||||
url: provider.getAuthUrl(
|
||||
JSON.stringify({ state, client, provider: unknownProviderName })
|
||||
),
|
||||
url: provider.getAuthUrl(stateStr, clientNonce),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -85,6 +91,7 @@ export class OAuthController {
|
||||
@Body('state') stateStr?: string,
|
||||
@Body('client_nonce') clientNonce?: string
|
||||
) {
|
||||
// TODO(@forehalo): refactor and remove deprecated code in 0.23
|
||||
if (!code) {
|
||||
throw new MissingOauthQueryParameter({ name: 'code' });
|
||||
}
|
||||
@@ -93,6 +100,17 @@ export class OAuthController {
|
||||
throw new MissingOauthQueryParameter({ name: 'state' });
|
||||
}
|
||||
|
||||
// NOTE(@forehalo): Apple sign in will directly post /callback, with `state` set at #L73
|
||||
let rawState = null;
|
||||
if (typeof stateStr === 'string' && stateStr.length > 36) {
|
||||
try {
|
||||
rawState = JSON.parse(stateStr);
|
||||
stateStr = rawState.state;
|
||||
} catch {
|
||||
/* noop */
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof stateStr !== 'string' || !this.oauth.isValidState(stateStr)) {
|
||||
throw new InvalidOauthCallbackState();
|
||||
}
|
||||
@@ -103,8 +121,38 @@ export class OAuthController {
|
||||
throw new OauthStateExpired();
|
||||
}
|
||||
|
||||
if (
|
||||
state.provider === OAuthProviderName.Apple &&
|
||||
rawState &&
|
||||
state.client &&
|
||||
state.client !== 'web'
|
||||
) {
|
||||
const clientUrl = new URL(`${state.client}://authentication`);
|
||||
clientUrl.searchParams.set('method', 'oauth');
|
||||
clientUrl.searchParams.set(
|
||||
'payload',
|
||||
JSON.stringify({
|
||||
state: stateStr,
|
||||
code,
|
||||
provider: rawState.provider,
|
||||
})
|
||||
);
|
||||
clientUrl.searchParams.set('server', this.url.origin);
|
||||
|
||||
return res.redirect(
|
||||
this.url.link('/open-app/url?', {
|
||||
url: clientUrl.toString(),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// TODO(@fengmk2): clientNonce should be required after the client version >= 0.21.0
|
||||
if (state.clientNonce && state.clientNonce !== clientNonce) {
|
||||
if (
|
||||
state.clientNonce &&
|
||||
state.clientNonce !== clientNonce &&
|
||||
// apple sign in with nonce stored in id token
|
||||
state.provider !== OAuthProviderName.Apple
|
||||
) {
|
||||
throw new InvalidAuthState();
|
||||
}
|
||||
|
||||
@@ -132,7 +180,8 @@ export class OAuthController {
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
const externAccount = await provider.getUser(tokens.accessToken);
|
||||
|
||||
const externAccount = await provider.getUser(tokens, state);
|
||||
const user = await this.loginFromOauth(
|
||||
state.provider,
|
||||
externAccount,
|
||||
@@ -140,6 +189,14 @@ export class OAuthController {
|
||||
);
|
||||
|
||||
await this.auth.setCookies(req, res, user.id);
|
||||
|
||||
if (
|
||||
state.provider === OAuthProviderName.Apple &&
|
||||
(!state.client || state.client === 'web')
|
||||
) {
|
||||
return res.redirect(this.url.link(state.redirectUri ?? '/'));
|
||||
}
|
||||
|
||||
res.send({
|
||||
id: user.id,
|
||||
redirectUri: state.redirectUri,
|
||||
@@ -170,7 +227,9 @@ export class OAuthController {
|
||||
userId: user.id,
|
||||
provider,
|
||||
providerAccountId: externalAccount.id,
|
||||
...tokens,
|
||||
accessToken: tokens.accessToken,
|
||||
refreshToken: tokens.refreshToken,
|
||||
expiresAt: tokens.expiresAt,
|
||||
});
|
||||
|
||||
return user;
|
||||
@@ -180,10 +239,11 @@ export class OAuthController {
|
||||
connectedAccount: ConnectedAccount,
|
||||
tokens: Tokens
|
||||
) {
|
||||
return await this.models.user.updateConnectedAccount(
|
||||
connectedAccount.id,
|
||||
tokens
|
||||
);
|
||||
return await this.models.user.updateConnectedAccount(connectedAccount.id, {
|
||||
accessToken: tokens.accessToken,
|
||||
refreshToken: tokens.refreshToken,
|
||||
expiresAt: tokens.expiresAt,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,7 +270,9 @@ export class OAuthController {
|
||||
userId: user.id,
|
||||
provider,
|
||||
providerAccountId: externalAccount.id,
|
||||
...tokens,
|
||||
accessToken: tokens.accessToken,
|
||||
refreshToken: tokens.refreshToken,
|
||||
expiresAt: tokens.expiresAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user