diff --git a/src/components/TokenForm/GitTokenForm.tsx b/src/components/TokenForm/GitTokenForm.tsx index dffc360b..3d81641c 100644 --- a/src/components/TokenForm/GitTokenForm.tsx +++ b/src/components/TokenForm/GitTokenForm.tsx @@ -10,6 +10,7 @@ import { useUserInfoObservable } from '@services/auth/hooks'; import { usePromiseValueAndSetter } from '@/helpers/useServiceValue'; import { APP_ID, APP_DOMAIN } from '@/constants/auth'; import { ServiceEmailTypes, ServiceTokenTypes, ServiceUserNameTypes } from '@services/auth/interface'; +import { useAuthing } from './gitTokenHooks'; const AuthingLoginButton = styled(Button)` white-space: nowrap; @@ -28,80 +29,12 @@ export function GitTokenForm(props: { const { children, storageService } = props; const { t } = useTranslation(); - /** - * Update tiddlywiki's editor user name when first time creating new workspace - */ - const [userName, userNameSetter] = usePromiseValueAndSetter( - async () => await window.service.auth.get('userName'), - async (newUserName) => await window.service.auth.set('userName', newUserName), - ); - - const authing = useMemo( - () => - new AuthingSSO({ - appId: APP_ID, - appDomain: APP_DOMAIN, - redirectUrl: 'http://localhost:3000', - }), - [], - ); + const authing = useAuthing(); const onFailure = useCallback((error: Error) => { console.error(error); }, []); - const onLoginSuccessResponse = useCallback( - async (response: ITrackSessionResult) => { - // DEBUG: console - console.log(`response`, response); - if ('userInfo' in response && response.userInfo?.thirdPartyIdentity?.accessToken !== undefined) { - const accessTokenToSet = response?.userInfo?.thirdPartyIdentity?.accessToken; - const authDataString = response?.userInfo?.oauth; - // all data we need - if (accessTokenToSet !== undefined && authDataString !== undefined) { - const authData = JSON.parse(authDataString); - // DEBUG: console - console.log(`authData`, authData); - const nextUserInfo: IAuthingUserInfo = { - ...response.userInfo, - ...authData, - ...response.userInfo?.thirdPartyIdentity, - }; - void window.service.auth.set(`${storageService}-token` as ServiceTokenTypes, accessTokenToSet); - void window.service.auth.set(`${storageService}-userName` as ServiceUserNameTypes, nextUserInfo.username); - void window.service.auth.set(`${storageService}-email` as ServiceEmailTypes, nextUserInfo.email); - if (userName === undefined || (userName === '' && nextUserInfo.username !== userName)) { - userNameSetter(nextUserInfo.username); - } - } - } - }, - [storageService, userName, userNameSetter], - ); - - const onClickLogout = useCallback(async () => { - const { code, message } = await authing.logout(); - await window.service.window.clearStorageData(); - if (code === 200) { - // TODO: clear the input - } else { - onFailure(new Error(message)); - } - }, [authing, onFailure]); - - // after authing redirect to 3rd party page and success, it will redirect back, we then check if login is success on component mount - useEffect(() => { - void (async () => { - const response = await authing.trackSession(); - // we logout so login into github won't block use from login into gitlab - await onClickLogout(); - const isLogin = response?.session !== undefined && response?.session !== null; - if (isLogin) { - await onLoginSuccessResponse(response); - } - })(); - }, [authing, onLoginSuccessResponse, onClickLogout]); - const onClickLogin = useCallback(async () => { // clear token first, otherwise github login window won't give us a chance to see the form // void this.auth.logout(); @@ -114,8 +47,6 @@ export function GitTokenForm(props: { }, [authing, onFailure]); const userInfo = useUserInfoObservable(); - // DEBUG: console - console.log(`userInfo`, JSON.stringify(userInfo)); if (userInfo === undefined) { return
Loading...
; } diff --git a/src/components/TokenForm/gitTokenHooks.ts b/src/components/TokenForm/gitTokenHooks.ts new file mode 100644 index 00000000..1831bb0b --- /dev/null +++ b/src/components/TokenForm/gitTokenHooks.ts @@ -0,0 +1,92 @@ +import { useCallback, useEffect, useMemo } from 'react'; +import AuthingSSO, { ITrackSessionResult } from '@authing/sso'; +import { ServiceTokenTypes, ServiceUserNameTypes, ServiceEmailTypes } from '@services/auth/interface'; +import { SupportedStorageServices, IAuthingUserInfo } from '@services/types'; +import { APP_ID, APP_DOMAIN } from '@/constants/auth'; +import { usePromiseValueAndSetter } from '@/helpers/useServiceValue'; + +export function useTokenFromAuthingRedirect(authing: AuthingSSO, callback?: () => void): void { + /** + * Update tiddlywiki's editor user name when first time creating new workspace + */ + const [userName, userNameSetter] = usePromiseValueAndSetter( + async () => await window.service.auth.get('userName'), + async (newUserName) => await window.service.auth.set('userName', newUserName), + ); + + const onLoginSuccessResponse = useCallback( + async (response: ITrackSessionResult) => { + // DEBUG: console + console.log(`response`, response); + if (!('userInfo' in response)) return; + const accessTokenToSet = response?.userInfo?.thirdPartyIdentity?.accessToken; + const provider = response?.userInfo?.thirdPartyIdentity?.provider as SupportedStorageServices; + if (accessTokenToSet !== undefined && provider !== undefined) { + if (!Object.values(SupportedStorageServices).includes(provider)) { + throw new Error(`${provider} not in SupportedStorageServices`); + } + // DEBUG: console + console.log(`provider`, provider); + const authDataString = response?.userInfo?.oauth; + // all data we need + if (accessTokenToSet !== undefined && authDataString !== undefined) { + const authData = JSON.parse(authDataString); + // DEBUG: console + console.log(`authData`, authData); + const nextUserInfo: IAuthingUserInfo = { + ...response.userInfo, + ...authData, + ...response.userInfo?.thirdPartyIdentity, + }; + await Promise.all([ + window.service.auth.set(`${provider}-token` as ServiceTokenTypes, accessTokenToSet), + window.service.auth.set(`${provider}-userName` as ServiceUserNameTypes, nextUserInfo.username), + window.service.auth.set(`${provider}-email` as ServiceEmailTypes, nextUserInfo.email), + ]); + callback(); + if (userName === undefined || (userName === '' && nextUserInfo.username !== userName)) { + userNameSetter(nextUserInfo.username); + } + } + } + }, + [userName, userNameSetter], + ); + + const onClickLogout = useCallback(async () => { + const { code, message } = await authing.logout(); + await window.service.window.clearStorageData(); + if (code === 200) { + // TODO: clear the input + } else { + throw new Error(message); + } + }, [authing]); + + // after authing redirect to 3rd party page and success, it will redirect back, we then check if login is success on component mount + useEffect(() => { + void (async () => { + const response = await authing.trackSession(); + // we logout so login into github won't block use from login into gitlab + await onClickLogout(); + const isLogin = response?.session !== undefined && response?.session !== null; + if (isLogin) { + await onLoginSuccessResponse(response); + } + })(); + }, [authing, onLoginSuccessResponse, onClickLogout]); +} + +export function useAuthing(): AuthingSSO { + const authing = useMemo( + () => + new AuthingSSO({ + appId: APP_ID, + appDomain: APP_DOMAIN, + redirectUrl: 'http://localhost:3000', + }), + [], + ); + + return authing; +} diff --git a/src/pages/AddWorkspace/index.tsx b/src/pages/AddWorkspace/index.tsx index 55e7c11d..384629fc 100644 --- a/src/pages/AddWorkspace/index.tsx +++ b/src/pages/AddWorkspace/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useCallback } from 'react'; import styled from 'styled-components'; import { useTranslation } from 'react-i18next'; import { AppBar, Paper, Tab } from '@material-ui/core'; @@ -16,6 +16,7 @@ import { CloneWikiForm } from './CloneWikiForm'; import { CloneWikiDoneButton } from './CloneWikiDoneButton'; import { useIsCreateMainWorkspace, useIsCreateSyncedWorkspace, useWikiWorkspaceForm } from './useForm'; +import { useAuthing, useTokenFromAuthingRedirect } from '@/components/TokenForm/gitTokenHooks'; enum CreateWorkspaceTabs { CloneOnlineWiki = 'CloneOnlineWiki', @@ -50,6 +51,12 @@ export default function AddWorkspace(): JSX.Element { const [isCreateSyncedWorkspace, isCreateSyncedWorkspaceSetter] = useIsCreateSyncedWorkspace(); const [isCreateMainWorkspace, isCreateMainWorkspaceSetter] = useIsCreateMainWorkspace(); + const authing = useAuthing(); + useTokenFromAuthingRedirect( + authing, + useCallback(() => isCreateSyncedWorkspaceSetter(true), []), + ); + const form = useWikiWorkspaceForm(); return ( diff --git a/src/preload/common/authing-postmessage.ts b/src/preload/common/authing-postmessage.ts index 741f021d..20f48380 100644 --- a/src/preload/common/authing-postmessage.ts +++ b/src/preload/common/authing-postmessage.ts @@ -44,6 +44,8 @@ interface IAuthingPostMessageEvent { window.addEventListener( 'message', (event: MessageEvent) => { + // DEBUG: console + console.log(`event`, event); if (typeof event?.data?.code === 'number' && typeof event?.data?.data?.token === 'string' && event?.data.from !== 'preload') { // This message will be catch by this handler again, so we add a 'from' to indicate that it is re-send by ourself // we re-send this, so authing in this window can catch it diff --git a/src/type.d.ts b/src/type.d.ts index 80256e7c..8bbd123c 100644 --- a/src/type.d.ts +++ b/src/type.d.ts @@ -41,6 +41,7 @@ declare module '@authing/sso' { oauth?: string; thirdPartyIdentity?: { accessToken?: string; + provider?: string; }; }