fix: not allow user to choose sub directory as jan data folder

Signed-off-by: James <james@jan.ai>
This commit is contained in:
James 2024-01-30 23:03:20 +07:00
parent 96aded6b03
commit 282dd58d05
5 changed files with 55 additions and 17 deletions

View File

@ -12,6 +12,7 @@ export enum AppRoute {
updateAppConfiguration = 'updateAppConfiguration', updateAppConfiguration = 'updateAppConfiguration',
relaunch = 'relaunch', relaunch = 'relaunch',
joinPath = 'joinPath', joinPath = 'joinPath',
isSubdirectory = 'isSubdirectory',
baseName = 'baseName', baseName = 'baseName',
startServer = 'startServer', startServer = 'startServer',
stopServer = 'stopServer', stopServer = 'stopServer',

View File

@ -22,7 +22,11 @@ const executeOnMain: (extension: string, method: string, ...args: any[]) => Prom
* @param {object} network - Optional object to specify proxy/whether to ignore SSL certificates. * @param {object} network - Optional object to specify proxy/whether to ignore SSL certificates.
* @returns {Promise<any>} A promise that resolves when the file is downloaded. * @returns {Promise<any>} A promise that resolves when the file is downloaded.
*/ */
const downloadFile: (url: string, fileName: string, network?: { proxy?: string, ignoreSSL?: boolean }) => Promise<any> = (url, fileName, network) => { const downloadFile: (
url: string,
fileName: string,
network?: { proxy?: string; ignoreSSL?: boolean }
) => Promise<any> = (url, fileName, network) => {
return global.core?.api?.downloadFile(url, fileName, network) return global.core?.api?.downloadFile(url, fileName, network)
} }
@ -87,6 +91,17 @@ const getResourcePath: () => Promise<string> = () => global.core.api?.getResourc
const log: (message: string, fileName?: string) => void = (message, fileName) => const log: (message: string, fileName?: string) => void = (message, fileName) =>
global.core.api?.log(message, fileName) global.core.api?.log(message, fileName)
/**
* Check whether the path is a subdirectory of another path.
*
* @param from - The path to check.
* @param to - The path to check against.
*
* @returns {Promise<boolean>} - A promise that resolves with a boolean indicating whether the path is a subdirectory.
*/
const isSubdirectory: (from: string, to: string) => Promise<boolean> = (from: string, to: string) =>
global.core.api?.isSubdirectory(from, to)
/** /**
* Register extension point function type definition * Register extension point function type definition
*/ */
@ -94,7 +109,7 @@ export type RegisterExtensionPoint = (
extensionName: string, extensionName: string,
extensionId: string, extensionId: string,
method: Function, method: Function,
priority?: number, priority?: number
) => void ) => void
/** /**
@ -111,5 +126,6 @@ export {
openExternalUrl, openExternalUrl,
baseName, baseName,
log, log,
isSubdirectory,
FileStat, FileStat,
} }

View File

@ -1,5 +1,5 @@
import { app, ipcMain, dialog, shell } from 'electron' import { app, ipcMain, dialog, shell } from 'electron'
import { join, basename } from 'path' import { join, basename, relative as getRelative, isAbsolute } from 'path'
import { WindowManager } from './../managers/window' import { WindowManager } from './../managers/window'
import { getResourcePath } from './../utils/path' import { getResourcePath } from './../utils/path'
import { AppRoute, AppConfiguration } from '@janhq/core' import { AppRoute, AppConfiguration } from '@janhq/core'
@ -50,6 +50,27 @@ export function handleAppIPCs() {
join(...paths) join(...paths)
) )
/**
* Checks if the given path is a subdirectory of the given directory.
*
* @param _event - The IPC event object.
* @param from - The path to check.
* @param to - The directory to check against.
*
* @returns {Promise<boolean>} - A promise that resolves with the result.
*/
ipcMain.handle(
AppRoute.isSubdirectory,
async (_event, from: string, to: string) => {
const relative = getRelative(from, to)
const isSubdir =
relative && !relative.startsWith('..') && !isAbsolute(relative)
if (isSubdir === '') return false
else return isSubdir
}
)
/** /**
* Retrieve basename from given path, respect to the current OS. * Retrieve basename from given path, respect to the current OS.
*/ */

View File

@ -10,15 +10,12 @@ import {
ModalClose, ModalClose,
Button, Button,
} from '@janhq/uikit' } from '@janhq/uikit'
import { atom, useAtom, useAtomValue } from 'jotai' import { atom, useAtom } from 'jotai'
import { errorAtom } from '.'
export const showChangeFolderErrorAtom = atom(false) export const showChangeFolderErrorAtom = atom(false)
const ModalErrorSetDestGlobal = () => { const ModalErrorSetDestGlobal = () => {
const [show, setShow] = useAtom(showChangeFolderErrorAtom) const [show, setShow] = useAtom(showChangeFolderErrorAtom)
const error = useAtomValue(errorAtom)
return ( return (
<Modal open={show} onOpenChange={setShow}> <Modal open={show} onOpenChange={setShow}>
<ModalPortal /> <ModalPortal />
@ -30,7 +27,6 @@ const ModalErrorSetDestGlobal = () => {
Oops! Something went wrong. Jan data folder remains the same. Please Oops! Something went wrong. Jan data folder remains the same. Please
try again. try again.
</p> </p>
<p className="text-muted-foreground">{error}</p>
<ModalFooter> <ModalFooter>
<div className="flex gap-x-2"> <div className="flex gap-x-2">
<ModalClose asChild onClick={() => setShow(false)}> <ModalClose asChild onClick={() => setShow(false)}>

View File

@ -1,8 +1,8 @@
import { Fragment, useCallback, useEffect, useState } from 'react' import { Fragment, useCallback, useEffect, useState } from 'react'
import { fs, AppConfiguration } from '@janhq/core' import { fs, AppConfiguration, isSubdirectory } from '@janhq/core'
import { Button, Input } from '@janhq/uikit' import { Button, Input } from '@janhq/uikit'
import { atom, useSetAtom } from 'jotai' import { useSetAtom } from 'jotai'
import { PencilIcon, FolderOpenIcon } from 'lucide-react' import { PencilIcon, FolderOpenIcon } from 'lucide-react'
import Loader from '@/containers/Loader' import Loader from '@/containers/Loader'
@ -18,8 +18,6 @@ import ModalErrorSetDestGlobal, {
import ModalSameDirectory, { showSamePathModalAtom } from './ModalSameDirectory' import ModalSameDirectory, { showSamePathModalAtom } from './ModalSameDirectory'
export const errorAtom = atom('')
const DataFolder = () => { const DataFolder = () => {
const [janDataFolderPath, setJanDataFolderPath] = useState('') const [janDataFolderPath, setJanDataFolderPath] = useState('')
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
@ -27,7 +25,6 @@ const DataFolder = () => {
const setShowSameDirectory = useSetAtom(showSamePathModalAtom) const setShowSameDirectory = useSetAtom(showSamePathModalAtom)
const setShowChangeFolderError = useSetAtom(showChangeFolderErrorAtom) const setShowChangeFolderError = useSetAtom(showChangeFolderErrorAtom)
const [destinationPath, setDestinationPath] = useState(undefined) const [destinationPath, setDestinationPath] = useState(undefined)
const setError = useSetAtom(errorAtom)
useEffect(() => { useEffect(() => {
window.core?.api window.core?.api
@ -46,6 +43,15 @@ const DataFolder = () => {
return return
} }
const appConfiguration: AppConfiguration =
await window.core?.api?.getAppConfigurations()
const currentJanDataFolder = appConfiguration.data_folder
if (await isSubdirectory(currentJanDataFolder, destFolder)) {
setShowSameDirectory(true)
return
}
setDestinationPath(destFolder) setDestinationPath(destFolder)
setShowDirectoryConfirm(true) setShowDirectoryConfirm(true)
}, [janDataFolderPath, setShowSameDirectory, setShowDirectoryConfirm]) }, [janDataFolderPath, setShowSameDirectory, setShowDirectoryConfirm])
@ -68,14 +74,12 @@ const DataFolder = () => {
setShowLoader(false) setShowLoader(false)
}, 1200) }, 1200)
await window.core?.api?.relaunch() await window.core?.api?.relaunch()
// eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (e) {
} catch (e: any) {
console.error(`Error: ${e}`) console.error(`Error: ${e}`)
setError(e.message)
setShowLoader(false) setShowLoader(false)
setShowChangeFolderError(true) setShowChangeFolderError(true)
} }
}, [destinationPath, setError, setShowChangeFolderError]) }, [destinationPath, setShowChangeFolderError])
return ( return (
<Fragment> <Fragment>