diff --git a/package.json b/package.json index b70033d..bff9a04 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "buffer": "^6.0.3", "crypto-browserify": "^3.12.0", "dropbox": "^10.22.0", + "emoji-regex": "^10.1.0", "http-status-codes": "^2.2.0", "localforage": "^1.10.0", "lodash": "^4.17.21", diff --git a/src/misc.ts b/src/misc.ts index b3fe267..686a803 100644 --- a/src/misc.ts +++ b/src/misc.ts @@ -3,6 +3,7 @@ import * as path from "path"; import { base32, base64url } from "rfc4648"; import XRegExp from "xregexp"; +import emojiRegex from "emoji-regex"; import { log } from "./moreOnLog"; @@ -162,6 +163,34 @@ export const isVaildText = (a: string) => { ); }; +/** + * Use regex to detect a text contains emoji or not. + * @param a + * @returns + */ +export const hasEmojiInText = (a: string) => { + const regex = emojiRegex(); + return regex.test(a); +}; + +/** + * Convert the headers to a normal object. + * @param h + * @param toLower + * @returns + */ +export const headersToRecord = (h: Headers, toLower: boolean = true) => { + const res: Record = {}; + h.forEach((v, k) => { + if (toLower) { + res[k.toLowerCase()] = v; + } else { + res[k] = v; + } + }); + return res; +}; + /** * If input is already a folder, returns it as is; * And if input is a file, returns its direname. diff --git a/src/remoteForDropbox.ts b/src/remoteForDropbox.ts index d88f337..df458e8 100644 --- a/src/remoteForDropbox.ts +++ b/src/remoteForDropbox.ts @@ -1,4 +1,4 @@ -import { Dropbox, DropboxAuth, files } from "dropbox"; +import { Dropbox, DropboxAuth, files, DropboxResponseError } from "dropbox"; import { Vault } from "obsidian"; import * as path from "path"; import { @@ -8,7 +8,13 @@ import { OAUTH2_FORCE_EXPIRE_MILLISECONDS, } from "./baseTypes"; import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt"; -import { bufferToArrayBuffer, getFolderLevels, mkdirpInVault } from "./misc"; +import { + bufferToArrayBuffer, + getFolderLevels, + hasEmojiInText, + headersToRecord, + mkdirpInVault, +} from "./misc"; export { Dropbox } from "dropbox"; @@ -338,6 +344,13 @@ export class WrappedDropboxClient { } if (!this.vaultFolderExists) { log.info(`remote does not have folder /${this.remoteBaseDir}`); + + if (hasEmojiInText(`/${this.remoteBaseDir}`)) { + throw new Error( + `/${this.remoteBaseDir}: Error: Dropbox does not support emoji in folder names.` + ); + } + await this.dropbox.filesCreateFolderV2({ path: `/${this.remoteBaseDir}`, }); @@ -423,6 +436,12 @@ export const uploadToRemote = async ( } uploadFile = getDropboxPath(uploadFile, client.remoteBaseDir); + if (hasEmojiInText(uploadFile)) { + throw new Error( + `${uploadFile}: Error: Dropbox does not support emoji in file / folder names.` + ); + } + const isFolder = fileOrFolderPath.endsWith("/"); if (isFolder && isRecursively) { @@ -442,7 +461,8 @@ export const uploadToRemote = async ( path: uploadFile, }); foldersCreatedBefore?.add(uploadFile); - } catch (err) { + } catch (e: unknown) { + const err = e as DropboxResponseError; if (err.status === 409) { // pass foldersCreatedBefore?.add(uploadFile); @@ -455,10 +475,23 @@ export const uploadToRemote = async ( return res; } else { // if encrypted, upload a fake file with the encrypted file name - await client.dropbox.filesUpload({ - path: uploadFile, - contents: "", - }); + try { + await client.dropbox.filesUpload({ + path: uploadFile, + contents: "", + }); + } catch (e: unknown) { + const err = e as DropboxResponseError; + // log.debug( + // `we are of error: ${JSON.stringify( + // headersToRecord(err.headers), + // null, + // 2 + // )}, ${err.status}, ${JSON.stringify(err.error, null, 2)}` + // ); + throw err; + } + return await getRemoteMeta(client, uploadFile); } } else { @@ -480,13 +513,33 @@ export const uploadToRemote = async ( } // in dropbox, we don't need to create folders before uploading! cool! // TODO: filesUploadSession for larger files (>=150 MB) - await client.dropbox.filesUpload({ - path: uploadFile, - contents: remoteContent, - mode: { - ".tag": "overwrite", - }, - }); + try { + await client.dropbox.filesUpload({ + path: uploadFile, + contents: remoteContent, + mode: { + ".tag": "overwrite", + }, + }); + } catch (e: unknown) { + const err = e as DropboxResponseError; + // log.debug( + // `we are of error: ${JSON.stringify( + // headersToRecord(err.headers), + // null, + // 2 + // )}, ${err.status}, ${JSON.stringify(err.error, null, 2)}` + // ); + // if (err.status === 429) { + // // too many request + // } else if (err.status === 409) { + // // Endpoint Specific Error + // } else { + // throw err; + // } + throw err; + } + // we want to mark that parent folders are created if (foldersCreatedBefore !== undefined) { const dirs = getFolderLevels(uploadFile).map((x) =>