mirror of
https://github.com/toeverything/AFFiNE.git
synced 2025-01-03 14:53:35 +03:00
feat: support google cloud login in client (#1822)
Co-authored-by: Himself65 <himself65@outlook.com> Co-authored-by: Peng Xiao <pengxiao@outlook.com>
This commit is contained in:
parent
024c469a2c
commit
c0669359ed
3
.github/workflows/release-desktop-app.yml
vendored
3
.github/workflows/release-desktop-app.yml
vendored
@ -40,6 +40,9 @@ env:
|
||||
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID }}
|
||||
NEXT_PUBLIC_FIREBASE_APP_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_APP_ID }}
|
||||
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID: ${{ secrets.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID }}
|
||||
AFFINE_GOOGLE_CLIENT_ID: ${{ secrets.AFFINE_GOOGLE_CLIENT_ID }}
|
||||
AFFINE_GOOGLE_CLIENT_SECRET: ${{ secrets.AFFINE_GOOGLE_CLIENT_SECRET }}
|
||||
NODE_API_SERVER: 'https://app.affine.pro'
|
||||
|
||||
jobs:
|
||||
make-macos:
|
||||
|
1
apps/electron/.gitignore
vendored
1
apps/electron/.gitignore
vendored
@ -11,3 +11,4 @@ resources/web-static
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
dev.json
|
||||
|
32
apps/electron/layers/main/src/app-state/google-auth.ts
Normal file
32
apps/electron/layers/main/src/app-state/google-auth.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import type { RequestInit } from 'undici';
|
||||
import { fetch, ProxyAgent } from 'undici';
|
||||
|
||||
const redirectUri = 'https://affine.pro/client/auth-callback';
|
||||
|
||||
export const oauthEndpoint = `https://accounts.google.com/o/oauth2/v2/auth?client_id=${process.env.AFFINE_GOOGLE_CLIENT_ID}&redirect_uri=${redirectUri}&response_type=code&scope=openid https://www.googleapis.com/auth/userinfo.email profile&access_type=offline`;
|
||||
|
||||
const tokenEndpoint = 'https://oauth2.googleapis.com/token';
|
||||
|
||||
export const exchangeToken = async (code: string) => {
|
||||
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
|
||||
const proxyAgent = httpProxy ? new ProxyAgent(httpProxy) : undefined;
|
||||
|
||||
const postData = {
|
||||
code,
|
||||
client_id: process.env.AFFINE_GOOGLE_CLIENT_ID || '',
|
||||
client_secret: process.env.AFFINE_GOOGLE_CLIENT_SECRET || '',
|
||||
redirect_uri: redirectUri,
|
||||
grant_type: 'authorization_code',
|
||||
};
|
||||
const requestOptions: RequestInit = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: new URLSearchParams(postData).toString(),
|
||||
dispatcher: proxyAgent,
|
||||
};
|
||||
return fetch(tokenEndpoint, requestOptions).then(response => {
|
||||
return response.json();
|
||||
});
|
||||
};
|
@ -2,13 +2,19 @@ import * as os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
import { Storage } from '@affine/octobase-node';
|
||||
import { app, shell } from 'electron';
|
||||
import { BrowserWindow, ipcMain, nativeTheme } from 'electron';
|
||||
import fs from 'fs-extra';
|
||||
import { parse } from 'url';
|
||||
|
||||
import { exchangeToken, oauthEndpoint } from './google-auth';
|
||||
|
||||
const AFFINE_ROOT = path.join(os.homedir(), '.affine');
|
||||
|
||||
fs.ensureDirSync(AFFINE_ROOT);
|
||||
|
||||
const logger = console;
|
||||
|
||||
// todo: rethink this
|
||||
export const appState = {
|
||||
storage: new Storage(path.join(AFFINE_ROOT, 'test.db')),
|
||||
@ -21,6 +27,7 @@ export const registerHandlers = () => {
|
||||
|
||||
ipcMain.handle('ui:theme-change', async (_, theme) => {
|
||||
nativeTheme.themeSource = theme;
|
||||
logger.info('theme change', theme);
|
||||
});
|
||||
|
||||
ipcMain.handle('ui:sidebar-visibility-change', async (_, visible) => {
|
||||
@ -30,5 +37,38 @@ export const registerHandlers = () => {
|
||||
// hide window buttons when sidebar is not visible
|
||||
w.setWindowButtonVisibility(visible);
|
||||
});
|
||||
logger.info('sidebar visibility change', visible);
|
||||
});
|
||||
|
||||
ipcMain.handle('ui:google-sign-in', async () => {
|
||||
logger.info('starting google sign in ...');
|
||||
shell.openExternal(oauthEndpoint);
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const handleOpenUrl = async (_: any, url: string) => {
|
||||
const mainWindow = BrowserWindow.getAllWindows().find(
|
||||
w => !w.isDestroyed()
|
||||
);
|
||||
const urlObj = parse(url.replace('??', '?'), true);
|
||||
if (!mainWindow || !url.startsWith('affine://')) return;
|
||||
const token = (await exchangeToken(urlObj.query['code'] as string)) as {
|
||||
id_token: string;
|
||||
};
|
||||
app.removeListener('open-url', handleOpenUrl);
|
||||
resolve(token.id_token);
|
||||
logger.info('google sign in', token);
|
||||
};
|
||||
|
||||
app.on('open-url', handleOpenUrl);
|
||||
|
||||
setTimeout(() => {
|
||||
reject(new Error('Timed out'));
|
||||
app.removeListener('open-url', handleOpenUrl);
|
||||
}, 60000);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.handle('main:env-update', async (_, env, value) => {
|
||||
process.env[env] = value;
|
||||
});
|
||||
};
|
||||
|
@ -1,11 +1,21 @@
|
||||
import './security-restrictions';
|
||||
|
||||
import { app } from 'electron';
|
||||
import path from 'path';
|
||||
|
||||
import { registerHandlers } from './app-state';
|
||||
import { restoreOrCreateWindow } from './main-window';
|
||||
import { registerProtocol } from './protocol';
|
||||
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('affine', process.execPath, [
|
||||
path.resolve(process.argv[1]),
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('affine');
|
||||
}
|
||||
/**
|
||||
* Prevent multiple instances
|
||||
*/
|
||||
@ -15,7 +25,13 @@ if (!isSingleInstance) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
app.on('second-instance', restoreOrCreateWindow);
|
||||
app.on('second-instance', (event, argv) => {
|
||||
restoreOrCreateWindow();
|
||||
});
|
||||
|
||||
app.on('open-url', async (_, url) => {
|
||||
// todo: handle `affine://...` urls
|
||||
});
|
||||
|
||||
/**
|
||||
* Disable Hardware Acceleration for more power-save
|
||||
@ -45,7 +61,6 @@ app
|
||||
.then(registerHandlers)
|
||||
.then(restoreOrCreateWindow)
|
||||
.catch(e => console.error('Failed create window:', e));
|
||||
|
||||
/**
|
||||
* Check new app version in production mode only
|
||||
*/
|
||||
|
@ -10,6 +10,14 @@ app.on('web-contents-created', (_, contents) => {
|
||||
* @see https://www.electronjs.org/docs/latest/tutorial/security#13-disable-or-limit-navigation
|
||||
*/
|
||||
contents.on('will-navigate', (event, url) => {
|
||||
if (
|
||||
(process.env.DEV_SERVER_URL &&
|
||||
url.startsWith(process.env.DEV_SERVER_URL)) ||
|
||||
url.startsWith('affine://') ||
|
||||
url.startsWith('file://.')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Prevent navigation
|
||||
event.preventDefault();
|
||||
shell.openExternal(url).catch(console.error);
|
||||
|
2
apps/electron/layers/preload/preload.d.ts
vendored
2
apps/electron/layers/preload/preload.d.ts
vendored
@ -7,6 +7,6 @@ interface Window {
|
||||
*
|
||||
* @see https://github.com/cawa-93/dts-for-context-bridge
|
||||
*/
|
||||
readonly apis: { workspaceSync: (id: string) => Promise<any>; onThemeChange: (theme: string) => Promise<any>; onSidebarVisibilityChange: (visible: boolean) => Promise<any>; };
|
||||
readonly apis: { workspaceSync: (id: string) => Promise<any>; onThemeChange: (theme: string) => Promise<any>; onSidebarVisibilityChange: (visible: boolean) => Promise<any>; googleSignIn: () => Promise<string>; updateEnv: (env: string, value: string) => void; };
|
||||
readonly appInfo: { electron: boolean; isMacOS: boolean; };
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ import { isMacOS } from '../../utils';
|
||||
*
|
||||
* @see https://github.com/cawa-93/dts-for-context-bridge
|
||||
*/
|
||||
|
||||
contextBridge.exposeInMainWorld('apis', {
|
||||
workspaceSync: (id: string) => ipcRenderer.invoke('octo:workspace-sync', id),
|
||||
// ui
|
||||
@ -30,6 +29,18 @@ contextBridge.exposeInMainWorld('apis', {
|
||||
|
||||
onSidebarVisibilityChange: (visible: boolean) =>
|
||||
ipcRenderer.invoke('ui:sidebar-visibility-change', visible),
|
||||
|
||||
/**
|
||||
* Try sign in using Google and return a Google IDToken
|
||||
*/
|
||||
googleSignIn: (): Promise<string> => ipcRenderer.invoke('ui:google-sign-in'),
|
||||
|
||||
/**
|
||||
* Secret backdoor to update environment variables in main process
|
||||
*/
|
||||
updateEnv: (env: string, value: string) => {
|
||||
ipcRenderer.invoke('main:env-update', env, value);
|
||||
},
|
||||
});
|
||||
|
||||
contextBridge.exposeInMainWorld('appInfo', {
|
||||
|
@ -36,6 +36,7 @@
|
||||
"@electron-forge/maker-zip": "^6.1.1",
|
||||
"@electron-forge/shared-types": "^6.1.1",
|
||||
"@electron/rebuild": "^3.2.10",
|
||||
"@electron/remote": "2.0.9",
|
||||
"dts-for-context-bridge": "^0.7.1",
|
||||
"electron": "24.0.0",
|
||||
"esbuild": "^0.17.16",
|
||||
@ -44,7 +45,19 @@
|
||||
"dependencies": {
|
||||
"cross-env": "7.0.3",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"fs-extra": "^11.1.1"
|
||||
"firebase": "^9.18.0",
|
||||
"fs-extra": "^11.1.1",
|
||||
"undici": "^5.21.2"
|
||||
},
|
||||
"build": {
|
||||
"protocols": [
|
||||
{
|
||||
"name": "affine",
|
||||
"schemes": [
|
||||
"affine"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"packageManager": "yarn@3.5.0"
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import * as url from 'node:url';
|
||||
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
||||
// const __dirname = new URL('.', import.meta.url).pathname;
|
||||
const { node } = JSON.parse(
|
||||
fs.readFileSync(
|
||||
path.join(__dirname, '../electron-vendors.autogen.json'),
|
||||
@ -20,22 +19,36 @@ const nativeNodeModulesPlugin = {
|
||||
},
|
||||
};
|
||||
|
||||
/** @type {import('esbuild').BuildOptions} */
|
||||
export const mainConfig = {
|
||||
entryPoints: ['layers/main/src/index.ts'],
|
||||
outdir: 'dist/layers/main',
|
||||
bundle: true,
|
||||
target: `node${node}`,
|
||||
platform: 'node',
|
||||
external: ['electron'],
|
||||
plugins: [nativeNodeModulesPlugin],
|
||||
};
|
||||
// List of env that will be replaced by esbuild
|
||||
const ENV_MACROS = ['AFFINE_GOOGLE_CLIENT_ID', 'AFFINE_GOOGLE_CLIENT_SECRET'];
|
||||
|
||||
export const preloadConfig = {
|
||||
entryPoints: ['layers/preload/src/index.ts'],
|
||||
outdir: 'dist/layers/preload',
|
||||
bundle: true,
|
||||
target: `node${node}`,
|
||||
platform: 'node',
|
||||
external: ['electron'],
|
||||
/** @return {{main: import('esbuild').BuildOptions, preload: import('esbuild').BuildOptions}} */
|
||||
export default () => {
|
||||
const define = Object.fromEntries(
|
||||
ENV_MACROS.map(key => [
|
||||
'process.env.' + key,
|
||||
JSON.stringify(process.env[key] ?? ''),
|
||||
])
|
||||
);
|
||||
return {
|
||||
main: {
|
||||
entryPoints: ['layers/main/src/index.ts'],
|
||||
outdir: 'dist/layers/main',
|
||||
bundle: true,
|
||||
target: `node${node}`,
|
||||
platform: 'node',
|
||||
external: ['electron'],
|
||||
plugins: [nativeNodeModulesPlugin],
|
||||
define: define,
|
||||
},
|
||||
preload: {
|
||||
entryPoints: ['layers/preload/src/index.ts'],
|
||||
outdir: 'dist/layers/preload',
|
||||
bundle: true,
|
||||
target: `node${node}`,
|
||||
platform: 'node',
|
||||
external: ['electron'],
|
||||
define: define,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -1,10 +1,16 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { generateAsync } from 'dts-for-context-bridge';
|
||||
import electronPath from 'electron';
|
||||
import * as esbuild from 'esbuild';
|
||||
|
||||
import { mainConfig, preloadConfig } from './common.mjs';
|
||||
import commonFn from './common.mjs';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
/** @type 'production' | 'development'' */
|
||||
const mode = (process.env.NODE_ENV = process.env.NODE_ENV || 'development');
|
||||
@ -17,6 +23,17 @@ const stderrFilterPatterns = [
|
||||
/ExtensionLoadWarning/,
|
||||
];
|
||||
|
||||
// these are set before calling commonFn so we have a chance to override them
|
||||
try {
|
||||
const devJson = readFileSync(path.resolve(__dirname, '../dev.json'), 'utf-8');
|
||||
const devEnv = JSON.parse(devJson);
|
||||
Object.assign(process.env, devEnv);
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
`Could not read dev.json. Some functions may not work as expected.`
|
||||
);
|
||||
}
|
||||
|
||||
// hard-coded for now:
|
||||
// fixme(xp): report error if app is not running on port 8080
|
||||
process.env.DEV_SERVER_URL = `http://localhost:8080`;
|
||||
@ -35,26 +52,28 @@ function spawnOrReloadElectron() {
|
||||
|
||||
spawnProcess.stdout.on(
|
||||
'data',
|
||||
d => d.toString().trim() && console.warn(d.toString(), { timestamp: true })
|
||||
d => d.toString().trim() && console.warn(d.toString())
|
||||
);
|
||||
spawnProcess.stderr.on('data', d => {
|
||||
const data = d.toString().trim();
|
||||
if (!data) return;
|
||||
const mayIgnore = stderrFilterPatterns.some(r => r.test(data));
|
||||
if (mayIgnore) return;
|
||||
console.error(data, { timestamp: true });
|
||||
console.error(data);
|
||||
});
|
||||
|
||||
// Stops the watch script when the application has been quit
|
||||
spawnProcess.on('exit', process.exit);
|
||||
}
|
||||
|
||||
const common = commonFn();
|
||||
|
||||
async function main() {
|
||||
async function watchPreload(onInitialBuild) {
|
||||
const preloadBuild = await esbuild.context({
|
||||
...preloadConfig,
|
||||
...common.preload,
|
||||
plugins: [
|
||||
...(preloadConfig.plugins ?? []),
|
||||
...(common.preload.plugins ?? []),
|
||||
{
|
||||
name: 'affine-dev:reload-app-on-preload-change',
|
||||
setup(build) {
|
||||
@ -81,13 +100,14 @@ async function main() {
|
||||
|
||||
async function watchMain() {
|
||||
const mainBuild = await esbuild.context({
|
||||
...mainConfig,
|
||||
...common.main,
|
||||
define: {
|
||||
...common.main.define,
|
||||
'process.env.NODE_ENV': `"${mode}"`,
|
||||
'process.env.DEV_SERVER_URL': `"${process.env.DEV_SERVER_URL}"`,
|
||||
},
|
||||
plugins: [
|
||||
...(mainConfig.plugins ?? []),
|
||||
...(common.main.plugins ?? []),
|
||||
{
|
||||
name: 'affine-dev:reload-app-on-main-change',
|
||||
setup(build) {
|
||||
|
@ -5,7 +5,7 @@ import path from 'node:path';
|
||||
|
||||
import * as esbuild from 'esbuild';
|
||||
|
||||
import { mainConfig, preloadConfig } from './common.mjs';
|
||||
import commonFn from './common.mjs';
|
||||
|
||||
const repoRootDir = path.join(__dirname, '..', '..', '..');
|
||||
const electronRootDir = path.join(__dirname, '..');
|
||||
@ -62,13 +62,13 @@ async function cleanup() {
|
||||
}
|
||||
|
||||
async function buildLayers() {
|
||||
await esbuild.build({
|
||||
...preloadConfig,
|
||||
});
|
||||
const common = commonFn();
|
||||
await esbuild.build(common.preload);
|
||||
|
||||
await esbuild.build({
|
||||
...mainConfig,
|
||||
...common.main,
|
||||
define: {
|
||||
...common.main.define,
|
||||
'process.env.NODE_ENV': `"production"`,
|
||||
},
|
||||
});
|
||||
|
@ -123,12 +123,15 @@ __metadata:
|
||||
"@electron-forge/maker-zip": ^6.1.1
|
||||
"@electron-forge/shared-types": ^6.1.1
|
||||
"@electron/rebuild": ^3.2.10
|
||||
"@electron/remote": 2.0.9
|
||||
cross-env: 7.0.3
|
||||
dts-for-context-bridge: ^0.7.1
|
||||
electron: 24.0.0
|
||||
electron-window-state: ^5.0.3
|
||||
esbuild: ^0.17.16
|
||||
firebase: ^9.18.0
|
||||
fs-extra: ^11.1.1
|
||||
undici: ^5.21.2
|
||||
zx: ^7.2.1
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
@ -2234,6 +2237,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@electron/remote@npm:2.0.9":
|
||||
version: 2.0.9
|
||||
resolution: "@electron/remote@npm:2.0.9"
|
||||
peerDependencies:
|
||||
electron: ">= 13.0.0"
|
||||
checksum: 7949c528df0ecc9661c0b43e7f2586befb9eddfb53739adf204dc2097ba4331fb08b01f6904636e4c566d28b051a80a55718fb643ee2d2df0793c0c05278dbd4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@electron/universal@npm:^1.3.2":
|
||||
version: 1.3.4
|
||||
resolution: "@electron/universal@npm:1.3.4"
|
||||
@ -7268,6 +7280,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"busboy@npm:^1.6.0":
|
||||
version: 1.6.0
|
||||
resolution: "busboy@npm:1.6.0"
|
||||
dependencies:
|
||||
streamsearch: ^1.1.0
|
||||
checksum: 32801e2c0164e12106bf236291a00795c3c4e4b709ae02132883fe8478ba2ae23743b11c5735a0aae8afe65ac4b6ca4568b91f0d9fed1fdbc32ede824a73746e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bytes@npm:3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "bytes@npm:3.0.0"
|
||||
@ -9636,7 +9657,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"firebase@npm:^9.19.1":
|
||||
"firebase@npm:^9.18.0, firebase@npm:^9.19.1":
|
||||
version: 9.19.1
|
||||
resolution: "firebase@npm:9.19.1"
|
||||
dependencies:
|
||||
@ -15960,6 +15981,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"streamsearch@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "streamsearch@npm:1.1.0"
|
||||
checksum: 1cce16cea8405d7a233d32ca5e00a00169cc0e19fbc02aa839959985f267335d435c07f96e5e0edd0eadc6d39c98d5435fb5bbbdefc62c41834eadc5622ad942
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"string-argv@npm:~0.3.1":
|
||||
version: 0.3.1
|
||||
resolution: "string-argv@npm:0.3.1"
|
||||
@ -16668,6 +16696,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"undici@npm:^5.21.2":
|
||||
version: 5.21.2
|
||||
resolution: "undici@npm:5.21.2"
|
||||
dependencies:
|
||||
busboy: ^1.6.0
|
||||
checksum: baceaa9e610966631e86ad2869b657556dd465438eed55e8079cec2a306ecbeecfde2d6e37e43baf96a4c59588ebef50476131e96e018dcc0a7f5db7e6a06c85
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unfetch@npm:^4.2.0":
|
||||
version: 4.2.0
|
||||
resolution: "unfetch@npm:4.2.0"
|
||||
|
@ -31,7 +31,6 @@ export const StyledHeader = styled('div')<{ hasWarning: boolean }>(
|
||||
padding: '0 20px',
|
||||
...displayFlex('space-between', 'center'),
|
||||
background: theme.colors.pageBackground,
|
||||
transition: 'background-color 0.5s',
|
||||
zIndex: 99,
|
||||
position: 'relative',
|
||||
};
|
||||
|
@ -12,8 +12,8 @@ import { jotaiStore } from '@affine/workspace/atom';
|
||||
import { isValidIPAddress } from '../utils';
|
||||
|
||||
let prefixUrl = '/';
|
||||
if (typeof window === 'undefined') {
|
||||
// SSR
|
||||
if (typeof window === 'undefined' || environment.isDesktop) {
|
||||
// SSR or Desktop
|
||||
const serverAPI = config.serverAPI;
|
||||
if (isValidIPAddress(serverAPI.split(':')[0])) {
|
||||
// This is for Server side rendering support
|
||||
@ -21,6 +21,7 @@ if (typeof window === 'undefined') {
|
||||
} else {
|
||||
prefixUrl = serverAPI;
|
||||
}
|
||||
prefixUrl = prefixUrl.endsWith('/') ? prefixUrl : prefixUrl + '/';
|
||||
} else {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.get('prefixUrl') && (prefixUrl = params.get('prefixUrl') as string);
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { getEnvironment } from '@affine/env';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { Slot } from '@blocksuite/store';
|
||||
import { initializeApp } from 'firebase/app';
|
||||
@ -9,6 +10,7 @@ import {
|
||||
getAuth as getFirebaseAuth,
|
||||
GithubAuthProvider,
|
||||
GoogleAuthProvider,
|
||||
signInWithCredential,
|
||||
signInWithPopup,
|
||||
} from 'firebase/auth';
|
||||
import { decode } from 'js-base64';
|
||||
@ -64,6 +66,13 @@ export const setLoginStorage = (login: LoginResponse) => {
|
||||
);
|
||||
};
|
||||
|
||||
const signInWithElectron = async (firebaseAuth: FirebaseAuth) => {
|
||||
const code = await window.apis?.googleSignIn();
|
||||
const credential = GoogleAuthProvider.credential(code);
|
||||
const user = await signInWithCredential(firebaseAuth, credential);
|
||||
return await user.user.getIdToken();
|
||||
};
|
||||
|
||||
export const clearLoginStorage = () => {
|
||||
localStorage.removeItem(STORAGE_KEY);
|
||||
};
|
||||
@ -152,6 +161,7 @@ export function createAffineAuth(prefix = '/') {
|
||||
method: SignMethod
|
||||
): Promise<LoginResponse | null> => {
|
||||
const auth = getAuth();
|
||||
const environment = getEnvironment();
|
||||
if (!auth) {
|
||||
throw new Error('Failed to initialize firebase');
|
||||
}
|
||||
@ -167,9 +177,14 @@ export function createAffineAuth(prefix = '/') {
|
||||
throw new Error('Unsupported sign method');
|
||||
}
|
||||
try {
|
||||
const response = await signInWithPopup(auth, provider);
|
||||
const idToken = await response.user.getIdToken();
|
||||
logger.debug(idToken);
|
||||
let idToken: string | undefined;
|
||||
if (environment.isDesktop) {
|
||||
idToken = await signInWithElectron(auth);
|
||||
} else {
|
||||
const response = await signInWithPopup(auth, provider);
|
||||
idToken = await response.user.getIdToken();
|
||||
}
|
||||
logger.debug('idToken', idToken);
|
||||
return fetch(prefix + 'api/user/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
|
@ -1,3 +1,5 @@
|
||||
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
||||
/// <reference path='../../../apps/electron/layers/preload/preload.d.ts' />
|
||||
import type { Workspace as RemoteWorkspace } from '@affine/workspace/affine/api';
|
||||
import type { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
|
Loading…
Reference in New Issue
Block a user