mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 20:38:52 +00:00
refactor: remove hacky email login (#4075)
Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
@@ -58,55 +58,11 @@ async function handleAffineUrl(url: string) {
|
||||
logger.info('handle affine schema action', urlObj.hostname);
|
||||
// handle more actions here
|
||||
// hostname is the action name
|
||||
if (urlObj.hostname === 'sign-in') {
|
||||
const urlToOpen = urlObj.search.slice(1);
|
||||
if (urlToOpen) {
|
||||
await handleSignIn(urlToOpen);
|
||||
}
|
||||
} else if (urlObj.hostname === 'oauth-jwt') {
|
||||
if (urlObj.hostname === 'oauth-jwt') {
|
||||
await handleOauthJwt(url);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: move to another place?
|
||||
async function handleSignIn(url: string) {
|
||||
if (url) {
|
||||
try {
|
||||
const mainWindow = await restoreOrCreateWindow();
|
||||
mainWindow.show();
|
||||
const urlObj = new URL(url);
|
||||
const email = urlObj.searchParams.get('email');
|
||||
|
||||
if (!email) {
|
||||
logger.error('no email in url', url);
|
||||
return;
|
||||
}
|
||||
|
||||
uiSubjects.onStartLogin.next({
|
||||
email,
|
||||
});
|
||||
const window = await handleOpenUrlInHiddenWindow(url);
|
||||
logger.info('opened url in hidden window', window.webContents.getURL());
|
||||
// check path
|
||||
// - if path === /auth/{signIn,signUp}, we know sign in succeeded
|
||||
// - if path === expired, we know sign in failed
|
||||
const finalUrl = new URL(window.webContents.getURL());
|
||||
console.log('final url', finalUrl);
|
||||
// hack: wait for the hidden window to send broadcast message to the main window
|
||||
// that's how next-auth works for cross-tab communication
|
||||
setTimeout(() => {
|
||||
window.destroy();
|
||||
}, 3000);
|
||||
uiSubjects.onFinishLogin.next({
|
||||
success: ['/auth/signIn', '/auth/signUp'].includes(finalUrl.pathname),
|
||||
email,
|
||||
});
|
||||
} catch (e) {
|
||||
logger.error('failed to open url in popup', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleOauthJwt(url: string) {
|
||||
if (url) {
|
||||
try {
|
||||
@@ -114,6 +70,7 @@ async function handleOauthJwt(url: string) {
|
||||
mainWindow.show();
|
||||
const urlObj = new URL(url);
|
||||
const token = urlObj.searchParams.get('token');
|
||||
const mainOrigin = new URL(mainWindow.webContents.getURL()).origin;
|
||||
|
||||
if (!token) {
|
||||
logger.error('no token in url', url);
|
||||
@@ -122,14 +79,22 @@ async function handleOauthJwt(url: string) {
|
||||
|
||||
// set token to cookie
|
||||
await setCookie({
|
||||
url: new URL(mainWindow.webContents.getURL()).origin,
|
||||
url: mainOrigin,
|
||||
httpOnly: true,
|
||||
value: token,
|
||||
name: 'next-auth.session-token',
|
||||
});
|
||||
|
||||
// force reload app
|
||||
mainWindow.webContents.reload();
|
||||
// hacks to refresh auth state in the main window
|
||||
const window = await handleOpenUrlInHiddenWindow(
|
||||
mainOrigin + '/auth/signIn'
|
||||
);
|
||||
uiSubjects.onFinishLogin.next({
|
||||
success: true,
|
||||
});
|
||||
setTimeout(() => {
|
||||
window.destroy();
|
||||
}, 3000);
|
||||
} catch (e) {
|
||||
logger.error('failed to open url in popup', e);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import electronWindowState from 'electron-window-state';
|
||||
import { join } from 'path';
|
||||
|
||||
import { isMacOS, isWindows } from '../shared/utils';
|
||||
import { CLOUD_BASE_URL } from './config';
|
||||
import { getExposedMeta } from './exposed';
|
||||
import { ensureHelperProcess } from './helper-process';
|
||||
import { logger } from './logger';
|
||||
@@ -115,7 +114,7 @@ async function createWindow() {
|
||||
/**
|
||||
* URL for main window.
|
||||
*/
|
||||
const pageUrl = CLOUD_BASE_URL; // see protocol.ts
|
||||
const pageUrl = process.env.DEV_SERVER_URL || 'file://.'; // see protocol.ts
|
||||
|
||||
logger.info('loading page at', pageUrl);
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ import { net, protocol, session } from 'electron';
|
||||
import { join } from 'path';
|
||||
|
||||
import { CLOUD_BASE_URL } from './config';
|
||||
import { setCookie } from './main-window';
|
||||
import { simpleGet } from './utils';
|
||||
|
||||
const NETWORK_REQUESTS = ['/api', '/ws', '/socket.io', '/graphql'];
|
||||
const webStaticDir = join(__dirname, '../resources/web-static');
|
||||
@@ -16,38 +14,16 @@ async function handleHttpRequest(request: Request) {
|
||||
const clonedRequest = Object.assign(request.clone(), {
|
||||
bypassCustomProtocolHandlers: true,
|
||||
});
|
||||
const { pathname, origin } = new URL(request.url);
|
||||
if (
|
||||
!origin.startsWith(CLOUD_BASE_URL) ||
|
||||
isNetworkResource(pathname) ||
|
||||
process.env.DEV_SERVER_URL // when debugging locally
|
||||
) {
|
||||
// note: I don't find a good way to get over with 302 redirect
|
||||
// by default in net.fetch, or don't know if there is a way to
|
||||
// bypass http request handling to browser instead ...
|
||||
if (pathname.startsWith('/api/auth/callback')) {
|
||||
const originResponse = await simpleGet(request.url);
|
||||
// hack: use window.webContents.session.cookies to set cookies
|
||||
// since return set-cookie header in response doesn't work here
|
||||
for (const [, cookie] of originResponse.headers.filter(
|
||||
p => p[0] === 'set-cookie'
|
||||
)) {
|
||||
await setCookie(origin, cookie);
|
||||
}
|
||||
return new Response(originResponse.body, {
|
||||
headers: originResponse.headers,
|
||||
status: originResponse.statusCode,
|
||||
});
|
||||
} else {
|
||||
// just pass through (proxy)
|
||||
return net.fetch(request.url, clonedRequest);
|
||||
}
|
||||
const urlObject = new URL(request.url);
|
||||
if (isNetworkResource(urlObject.pathname)) {
|
||||
// just pass through (proxy)
|
||||
return net.fetch(CLOUD_BASE_URL + urlObject.pathname, clonedRequest);
|
||||
} else {
|
||||
// this will be file types (in the web-static folder)
|
||||
let filepath = '';
|
||||
// if is a file type, load the file in resources
|
||||
if (pathname.split('/').at(-1)?.includes('.')) {
|
||||
filepath = join(webStaticDir, decodeURIComponent(pathname));
|
||||
if (urlObject.pathname.split('/').at(-1)?.includes('.')) {
|
||||
filepath = join(webStaticDir, decodeURIComponent(urlObject.pathname));
|
||||
} else {
|
||||
// else, fallback to load the index.html instead
|
||||
filepath = join(webStaticDir, 'index.html');
|
||||
@@ -57,11 +33,7 @@ async function handleHttpRequest(request: Request) {
|
||||
}
|
||||
|
||||
export function registerProtocol() {
|
||||
protocol.handle('http', request => {
|
||||
return handleHttpRequest(request);
|
||||
});
|
||||
|
||||
protocol.handle('https', request => {
|
||||
protocol.handle('file', request => {
|
||||
return handleHttpRequest(request);
|
||||
});
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@ import { uiSubjects } from './subject';
|
||||
*/
|
||||
export const uiEvents = {
|
||||
onFinishLogin: (
|
||||
fn: (result: { success: boolean; email: string }) => void
|
||||
fn: (result: { success: boolean; email?: string }) => void
|
||||
) => {
|
||||
const sub = uiSubjects.onFinishLogin.subscribe(fn);
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
};
|
||||
},
|
||||
onStartLogin: (fn: (opts: { email: string }) => void) => {
|
||||
onStartLogin: (fn: (opts: { email?: string }) => void) => {
|
||||
const sub = uiSubjects.onStartLogin.subscribe(fn);
|
||||
return () => {
|
||||
sub.unsubscribe();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
export const uiSubjects = {
|
||||
onStartLogin: new Subject<{ email: string }>(),
|
||||
onFinishLogin: new Subject<{ success: boolean; email: string }>(),
|
||||
onStartLogin: new Subject<{ email?: string }>(),
|
||||
onFinishLogin: new Subject<{ success: boolean; email?: string }>(),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user