refactor: remove hacky email login (#4075)

Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
Peng Xiao
2023-09-01 01:49:22 +08:00
committed by GitHub
parent f99a7a5ecd
commit a2e4ef904b
13 changed files with 78 additions and 153 deletions

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
});

View File

@@ -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();

View File

@@ -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 }>(),
};