fix: FTP access to deep subdirectories and pb_migrations

This commit is contained in:
Ben Allfree 2023-06-07 23:40:49 -07:00
parent 04deecf8fd
commit a601e53430
2 changed files with 51 additions and 41 deletions

View File

@ -17,6 +17,7 @@ export type FtpConfig = {}
export enum FolderNames {
PbData = 'pb_data',
PbStatic = 'pb_static',
PbMigrations = 'pb_migrations',
PbWorker = 'worker',
PbBackup = 'backup',
}
@ -26,6 +27,7 @@ export const README_CONTENTS: { [_ in FolderNames]: string } = {
[FolderNames.PbData]: `This directory contains your PocketBase data. For more information, see https://pockethost.io/docs/data`,
[FolderNames.PbStatic]: `This directory contains static files such as your web frontend. PocketHost will serve these when your instance URL receives a request. For more information, see https://pockethost.io/docs/static `,
[FolderNames.PbWorker]: `This directory contains your Deno worker. For more information, see https://pockethost.io/docs/workers`,
[FolderNames.PbMigrations]: `This directory contains your migrations. For more information, see https://pockethost.io/docs/migrations`,
}
export const README_NAME = 'readme.md'
@ -34,6 +36,7 @@ export const FOLDER_NAMES: FolderNames[] = [
FolderNames.PbData,
FolderNames.PbStatic,
FolderNames.PbWorker,
FolderNames.PbMigrations,
]
export function isFolder(name: string): name is FolderNames {

View File

@ -47,8 +47,8 @@ export class PhFs extends FileSystem {
throw new Error(`Expected path`)
}
const _path = path.startsWith('/') ? path : join(this.cwd, path)
const [empty, subdomain, folderName] = _path.split('/')
this.log.dbg({ _path, subdomain, folderName })
const [empty, subdomain, folderName, ...restOfPath] = _path.split('/')
this.log.dbg({ _path, subdomain, folderName, restOfPath })
if (subdomain === '') {
const instances = await this.client.getInstances()
@ -62,49 +62,48 @@ export class PhFs extends FileSystem {
}
})
}
if (subdomain) {
const [instance, user] = await this.client.getInstanceBySubdomain(
subdomain
)
if (!instance) {
throw new Error(`Expected instance here`)
}
if (!folderName) {
return FOLDER_NAMES.map((name) => ({
isDirectory: () => true,
mode: 0o755,
size: 0,
mtime: Date.parse(instance.updated),
name: name,
}))
}
if (isFolder(folderName)) {
const dir = join(DAEMON_PB_DATA_DIR, instance.id, folderName)
this.log.dbg({ dir, exists: existsSync(dir) })
return [
{
isDirectory: () => false,
mode: 0o444,
size: README_CONTENTS[folderName].length,
mtime: Date.parse(instance.updated),
name: README_NAME,
},
...(existsSync(dir)
? await super.list(
join(DAEMON_PB_DATA_DIR, instance.id, folderName)
)
: []),
]
}
if (!subdomain) {
throw new Error(`Subdomain expected in ${_path}`)
}
throw new Error(`Error parsing ${_path}`)
const [instance, user] = await this.client.getInstanceBySubdomain(subdomain)
if (!instance) {
throw new Error(`Expected instance here`)
}
if (!folderName) {
return FOLDER_NAMES.map((name) => ({
isDirectory: () => true,
mode: 0o755,
size: 0,
mtime: Date.parse(instance.updated),
name: name,
}))
}
if (!isFolder(folderName)) {
throw new Error(`Top level folder name ${folderName} not allowed.`)
}
const dir = join(DAEMON_PB_DATA_DIR, instance.id, folderName, ...restOfPath)
this.log.dbg({ dir, exists: existsSync(dir) })
return [
...(restOfPath.length === 0
? [
{
isDirectory: () => false,
mode: 0o444,
size: README_CONTENTS[folderName].length,
mtime: Date.parse(instance.updated),
name: README_NAME,
},
]
: []),
...(existsSync(dir) ? await super.list(dir) : []),
]
}
async get(fileName: string): Promise<FileStat> {
const _path = fileName.startsWith('/') ? fileName : join(this.cwd, fileName)
const [empty, subdomain, folderName, ...fNames] = _path.split('/')
const path = fileName.startsWith('/') ? fileName : join(this.cwd, fileName)
const [empty, subdomain, folderName, ...fNames] = path.split('/')
const fName = fNames.join('/')
this.log.dbg(`get`, { _path, subdomain, folderName, fName, fileName })
this.log.dbg(`get`, { _path: path, subdomain, folderName, fName, fileName })
if (!subdomain) {
return {
@ -140,7 +139,15 @@ export class PhFs extends FileSystem {
name: folderName,
}
}
return super.get(_path)
const physicalPath = join(
DAEMON_PB_DATA_DIR,
instance.id,
folderName,
fName
)
this.log.dbg({ physicalPath, exists: existsSync(physicalPath) })
return super.get(physicalPath)
}
async write(