diff --git a/packages/data-center/src/apis/token.ts b/packages/data-center/src/apis/token.ts index b0acf68ee..c509da0f3 100644 --- a/packages/data-center/src/apis/token.ts +++ b/packages/data-center/src/apis/token.ts @@ -60,7 +60,9 @@ class Token { } async initToken(token: string) { - this._setToken(await login({ token, type: 'Google' })); + const tokens = await login({ token, type: 'Google' }); + this._setToken(tokens); + return this._user; } async refreshToken(token?: string) { @@ -153,10 +155,27 @@ export const getAuthorizer = () => { const googleAuthProvider = new GoogleAuthProvider(); + const getToken = async () => { + const currentUser = firebaseAuth.currentUser; + if (currentUser) { + await currentUser.getIdTokenResult(true); + if (!currentUser.isAnonymous) { + return currentUser.getIdToken(); + } + } + return; + }; + const signInWithGoogle = async () => { - const user = await signInWithPopup(firebaseAuth, googleAuthProvider); - const idToken = await user.user.getIdToken(); - await token.initToken(idToken); + const idToken = await getToken(); + if (idToken) { + await token.initToken(idToken); + } else { + const user = await signInWithPopup(firebaseAuth, googleAuthProvider); + const idToken = await user.user.getIdToken(); + await token.initToken(idToken); + } + return firebaseAuth.currentUser; }; const onAuthStateChanged = (callback: (user: User | null) => void) => { diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 62edea334..a094b9def 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -97,6 +97,21 @@ export class DataCenter { return provider; } + async auth(providerId: string, globalConfig?: Record) { + const Provider = this._providers.get(providerId); + if (Provider) { + // initial configurator + const config = getKVConfigure(`provider:${providerId}`); + // set workspace configs + const values = Object.entries(globalConfig || {}); + if (values.length) await config.setMany(values); + + const logger = this._logger.extend(`auth:${providerId}`); + logger.enabled = this._logger.enabled; + await Provider.auth(config, logger); + } + } + /** * load workspace data to memory * @param workspaceId workspace id diff --git a/packages/data-center/src/index.ts b/packages/data-center/src/index.ts index 68aa74b91..72aa6015e 100644 --- a/packages/data-center/src/index.ts +++ b/packages/data-center/src/index.ts @@ -7,6 +7,10 @@ const _initializeDataCenter = () => { return (debug = true) => { if (!_dataCenterInstance) { _dataCenterInstance = DataCenter.init(debug); + _dataCenterInstance.then(dc => { + (window as any).dc = dc; + return dc; + }); } return _dataCenterInstance; diff --git a/packages/data-center/src/provider/affine/index.ts b/packages/data-center/src/provider/affine/index.ts index fef7a4d0a..6f1824a15 100644 --- a/packages/data-center/src/provider/affine/index.ts +++ b/packages/data-center/src/provider/affine/index.ts @@ -1,8 +1,8 @@ import assert from 'assert'; import { applyUpdate } from 'yjs'; -import type { InitialParams } from '../index.js'; -import { token, Callback } from '../../apis/index.js'; +import type { ConfigStore, InitialParams, Logger } from '../index.js'; +import { token, Callback, getApis } from '../../apis/index.js'; import { LocalProvider } from '../local/index.js'; import { WebsocketProvider } from './sync.js'; @@ -91,4 +91,26 @@ export class AffineProvider extends LocalProvider { // just a workaround for yjs doc.getMap('space:meta'); } + + static async auth(config: Readonly>, logger: Logger) { + const refreshToken = await config.get('token'); + if (refreshToken) { + await token.refreshToken(refreshToken); + if (token.isLogin && !token.isExpired) { + logger('check login success'); + // login success + return; + } + } + + logger('start login'); + // login with google + const apis = getApis(); + assert(apis.signInWithGoogle); + const user = await apis.signInWithGoogle(); + assert(user); + logger(`login success: ${user.displayName}`); + + // TODO: refresh local workspace data + } } diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 95bd309a1..8ed184b6e 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -55,6 +55,10 @@ export class BaseProvider { return this._workspace; } + static async auth(_config: Readonly, _logger: Logger) { + throw Error('Not implemented: auth'); + } + // get workspace list,return a map of workspace id and boolean // if value is true, it exists locally, otherwise it does not exist locally static async list( diff --git a/packages/data-center/src/provider/local/index.ts b/packages/data-center/src/provider/local/index.ts index d2ced1b9e..89ec6ce19 100644 --- a/packages/data-center/src/provider/local/index.ts +++ b/packages/data-center/src/provider/local/index.ts @@ -1,7 +1,7 @@ import type { BlobStorage } from '@blocksuite/store'; import assert from 'assert'; -import type { ConfigStore, InitialParams } from '../index.js'; +import type { ConfigStore, InitialParams, Logger } from '../index.js'; import { BaseProvider } from '../base.js'; import { IndexedDBProvider } from './indexeddb.js'; @@ -32,14 +32,14 @@ export class LocalProvider extends BaseProvider { await this._idb.whenSynced; this._logger('Local data loaded'); - await this._globalConfig.set(this._workspace.room, true); + await this._globalConfig.set(`list:${this._workspace.room}`, true); } async clear() { await super.clear(); await this._blobs.clear(); await this._idb?.clearData(); - await this._globalConfig.delete(this._workspace.room!); + await this._globalConfig.delete(`list:${this._workspace.room}`); } async destroy(): Promise { @@ -55,10 +55,18 @@ export class LocalProvider extends BaseProvider { return this._blobs.set(blob); } + static async auth(_config: Readonly, logger: Logger) { + logger("Local provider doesn't require authentication"); + } + static async list( config: Readonly> ): Promise | undefined> { const entries = await config.entries(); - return new Map(entries); + return new Map( + entries + .filter(([key]) => key.startsWith('list:')) + .map(([key, value]) => [key.slice(5), value]) + ); } }