diff --git a/source/main/services/googleDrive.ts b/source/main/services/googleDrive.ts index fa570f7c..1e6e0abd 100644 --- a/source/main/services/googleDrive.ts +++ b/source/main/services/googleDrive.ts @@ -8,7 +8,6 @@ import { logInfo, logWarn } from "../library/log"; import { GOOGLE_AUTH_REDIRECT, GOOGLE_AUTH_TIMEOUT, - GOOGLE_DRIVE_SCOPES_PERMISSIVE, GOOGLE_DRIVE_SCOPES_STANDARD, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET @@ -25,11 +24,9 @@ export function addGoogleTokens( __googleDriveTokens[sourceID] = tokens; } -async function authenticateGoogleDrive( - openPermissions: boolean = false -): Promise<{ accessToken: string; refreshToken: string }> { - logInfo(`Authenticating Google Drive (permissive: ${openPermissions ? "yes" : "no"})`); - const scopes = openPermissions ? GOOGLE_DRIVE_SCOPES_PERMISSIVE : GOOGLE_DRIVE_SCOPES_STANDARD; +async function authenticateGoogleDrive(): Promise<{ accessToken: string; refreshToken: string }> { + logInfo("Authenticating Google Drive"); + const scopes = GOOGLE_DRIVE_SCOPES_STANDARD; const oauth2Client = getGoogleDriveOAuthClient(); const url = oauth2Client.generateAuthUrl({ access_type: "offline", diff --git a/source/renderer/actions/addVault.ts b/source/renderer/actions/addVault.ts index 8136d7e4..f8e40697 100644 --- a/source/renderer/actions/addVault.ts +++ b/source/renderer/actions/addVault.ts @@ -13,7 +13,7 @@ export async function addNewVaultTarget( datasourceConfig: DatasourceConfig, password: string, createNew: boolean, - fileNameOverride: string = null + fileNameOverride: string | null = null ): Promise { setBusy(true); const addNewVaultPromise = new Promise((resolve, reject) => { diff --git a/source/renderer/components/AddVaultMenu.tsx b/source/renderer/components/AddVaultMenu.tsx index 22a80f66..8e6db2fe 100644 --- a/source/renderer/components/AddVaultMenu.tsx +++ b/source/renderer/components/AddVaultMenu.tsx @@ -11,11 +11,12 @@ import { testWebDAV } from "../actions/webdav"; import { getFSInstance } from "../library/fsInterface"; import { FileChooser } from "./standalone/FileChooser"; import { addNewVaultTarget, getFileVaultParameters } from "../actions/addVault"; -import { showError } from "../services/notifications"; -import { authenticateGoogleDrive } from "../services/authGoogle"; +import { showError, showSuccess } from "../services/notifications"; +import { authenticateGoogleDrive, getGoogleDriveAuthURL, waitForGoogleAuthCode } from "../services/authGoogle"; import { createEmptyVault as createEmptyGoogleDriveVault } from "../services/googleDrive"; import { showWarning } from "../services/notifications"; import { getIconForProvider } from "../library/icons"; +import { copyText } from "../actions/clipboard"; import { t } from "../../shared/i18n/trans"; import { DatasourceConfig, SourceType } from "../types"; @@ -25,9 +26,9 @@ interface WebDAVCredentialsState { password: string; } -const { useCallback, useEffect, useState } = React; +const { Fragment, useCallback, useEffect, useState } = React; -const EMPTY_DATASOURCE_CONFIG = { type: null }; +const EMPTY_DATASOURCE_CONFIG: DatasourceConfig = { type: null }; const EMPTY_WEBDAV_CREDENTIALS: WebDAVCredentialsState = { url: "", username: "", password: "" }; const PAGE_TYPE = "type"; const PAGE_AUTH = "auth"; @@ -110,16 +111,15 @@ export function AddVaultMenu() { const showAddVault = useHookState(SHOW_ADD_VAULT); const [previousShowAddVault, setPreviousShowAddVault] = useState(false); const [currentPage, setCurrentPage] = useState(PAGE_TYPE); - const [selectedType, setSelectedType] = useState(null); - const [selectedRemotePath, setSelectedRemotePath] = useState(null); + const [selectedType, setSelectedType] = useState(null); + const [selectedRemotePath, setSelectedRemotePath] = useState(null); const [datasourcePayload, setDatasourcePayload] = useState({ ...EMPTY_DATASOURCE_CONFIG }); - const [fsInstance, setFsInstance] = useState(null); + const [fsInstance, setFsInstance] = useState(null); const [createNew, setCreateNew] = useState(false); const [vaultPassword, setVaultPassword] = useState(""); const [webdavCredentials, setWebDAVCredentials] = useState({ ...EMPTY_WEBDAV_CREDENTIALS }); const [authenticatingGoogleDrive, setAuthenticatingGoogleDrive] = useState(false); - const [googleDriveOpenPerms, setGoogleDriveOpenPerms] = useState(false); - const [vaultFilenameOverride, setVaultFilenameOverride] = useState(null); + const [vaultFilenameOverride, setVaultFilenameOverride] = useState(null); useEffect(() => { const newValue = showAddVault.get(); if (previousShowAddVault !== newValue) { @@ -136,7 +136,6 @@ export function AddVaultMenu() { setDatasourcePayload({ ...EMPTY_DATASOURCE_CONFIG }); setWebDAVCredentials({ ...EMPTY_WEBDAV_CREDENTIALS }); setVaultPassword(""); - setGoogleDriveOpenPerms(false); setAuthenticatingGoogleDrive(false); setVaultFilenameOverride(null); }, []); @@ -194,7 +193,7 @@ export function AddVaultMenu() { const handleAuthSubmit = useCallback(async () => { if (selectedType === SourceType.GoogleDrive) { try { - const { accessToken, refreshToken } = await authenticateGoogleDrive(googleDriveOpenPerms); + const { accessToken, refreshToken } = await authenticateGoogleDrive(); setDatasourcePayload({ ...datasourcePayload, token: accessToken, @@ -235,8 +234,35 @@ export function AddVaultMenu() { setFsInstance(getFSInstance(SourceType.WebDAV, newPayload)); setCurrentPage(PAGE_CHOOSE); } - }, [selectedType, datasourcePayload, webdavCredentials, googleDriveOpenPerms]); - const handleSelectedPathChange = useCallback((parentIdentifier: string | null, identifier: string, isNew: boolean, fileName: string | null) => { + }, [selectedType, datasourcePayload, webdavCredentials]); + const handleAuthURLCopy = useCallback(async () => { + if (selectedType === SourceType.GoogleDrive) { + const url = getGoogleDriveAuthURL(); + try { + await copyText(url); + showSuccess(t("add-vault-menu.copy-auth-link.url-copied")); + } catch (err) { + showError(err.message); + } + try { + const { accessToken, refreshToken } = await waitForGoogleAuthCode(); + setDatasourcePayload({ + ...datasourcePayload, + token: accessToken, + refreshToken + }); + setFsInstance(getFSInstance(SourceType.GoogleDrive, { + token: accessToken + })); + setCurrentPage(PAGE_CHOOSE); + } catch (err) { + console.error(err); + showWarning(`${t("add-vault-menu.google-auth-error")}: ${err.message}`); + setAuthenticatingGoogleDrive(false); + } + } + }, [selectedType, datasourcePayload]); + const handleSelectedPathChange = useCallback((parentIdentifier: string | number | null, identifier: string, isNew: boolean, fileName: string | null) => { if (selectedType === SourceType.GoogleDrive) { setSelectedRemotePath(JSON.stringify([parentIdentifier, identifier])); setVaultFilenameOverride(fileName); @@ -271,7 +297,7 @@ export function AddVaultMenu() { }, [selectedRemotePath, selectedType, datasourcePayload]); const handleFinalConfirm = useCallback(async () => { const datasource = { ...datasourcePayload }; - if (selectedType === SourceType.GoogleDrive) { + if (selectedType === SourceType.GoogleDrive && selectedRemotePath && datasource.token) { const [parentIdentifier, identifier] = JSON.parse(selectedRemotePath); datasource.fileID = createNew ? await createEmptyGoogleDriveVault(datasource.token, parentIdentifier, identifier, vaultPassword) @@ -311,17 +337,6 @@ export function AddVaultMenu() {

- - ) => setGoogleDriveOpenPerms(evt.target.checked)} - /> - )} {selectedType === SourceType.WebDAV && ( @@ -418,14 +433,23 @@ export function AddVaultMenu() { )} {currentPage === PAGE_AUTH && selectedType === SourceType.GoogleDrive && ( - + + + + )} {currentPage === PAGE_AUTH && selectedType === SourceType.WebDAV && (