mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-02-24 04:00:59 +01:00
feat: add attachment upload & download
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"@rebass/forms": "^4.0.6",
|
||||
"@streetwritersco/tinymce-plugins": "file:../notesnook/packages/tinymce-plugins",
|
||||
"@tinymce/tinymce-react": "^3.12.6",
|
||||
"axios": "^0.21.4",
|
||||
"clipboard": "^2.0.6",
|
||||
"cogo-toast": "^4.2.3",
|
||||
"compressorjs": "^1.0.7",
|
||||
|
||||
@@ -188,7 +188,7 @@ const decrypt = (passwordOrKey, { iv, cipher, salt, output, inputType }) => {
|
||||
const { key } = _getKey({ salt, ...passwordOrKey });
|
||||
const input =
|
||||
inputType === "uint8array"
|
||||
? input
|
||||
? cipher
|
||||
: inputType === "base64"
|
||||
? sodium.from_base64(cipher)
|
||||
: sodium.decode(cipher);
|
||||
@@ -199,10 +199,12 @@ const decrypt = (passwordOrKey, { iv, cipher, salt, output, inputType }) => {
|
||||
undefined,
|
||||
sodium.from_base64(iv),
|
||||
key,
|
||||
output
|
||||
output !== "base64" ? output : "uint8array"
|
||||
);
|
||||
sodium.memzero(key);
|
||||
return data;
|
||||
return output === "base64"
|
||||
? sodium.to_base64(data, sodium.base64_variants.ORIGINAL)
|
||||
: data;
|
||||
};
|
||||
|
||||
if (self.document) {
|
||||
|
||||
@@ -47,7 +47,7 @@ async function pickFile() {
|
||||
const key = await getEncryptionKey();
|
||||
const buffer = await selectedFile.arrayBuffer();
|
||||
const output = await fs.writeEncrypted(null, {
|
||||
data: buffer,
|
||||
data: new Uint8Array(buffer),
|
||||
type: "buffer",
|
||||
key,
|
||||
});
|
||||
@@ -59,7 +59,7 @@ async function pickFile() {
|
||||
});
|
||||
|
||||
return {
|
||||
hash: selectedFile.hash,
|
||||
hash: output.hash,
|
||||
filename: selectedFile.name,
|
||||
type: selectedFile.type,
|
||||
size: selectedFile.size,
|
||||
@@ -74,7 +74,7 @@ async function pickImage() {
|
||||
const key = await getEncryptionKey();
|
||||
|
||||
const output = await fs.writeEncrypted(null, {
|
||||
data: buffer,
|
||||
data: new Uint8Array(buffer),
|
||||
type: "buffer",
|
||||
key,
|
||||
});
|
||||
@@ -86,7 +86,7 @@ async function pickImage() {
|
||||
});
|
||||
|
||||
return {
|
||||
hash: selectedImage.hash,
|
||||
hash: output.hash,
|
||||
filename: selectedImage.name,
|
||||
type: selectedImage.type,
|
||||
size: output.length,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import NNCrypto from "./nncrypto/index";
|
||||
import localforage from "localforage";
|
||||
import xxhash from "xxhash-wasm";
|
||||
import axios from "axios";
|
||||
|
||||
const crypto = new NNCrypto();
|
||||
const fs = localforage.createInstance({
|
||||
@@ -48,12 +49,13 @@ async function writeEncrypted(filename, { data, type, key }) {
|
||||
async function hashBuffer(data) {
|
||||
const hasher = await xxhash();
|
||||
return {
|
||||
hash: Buffer.from(hasher.h64Raw(data)).toString("base64"),
|
||||
hash: Buffer.from(hasher.h64Raw(data)).toString("hex"),
|
||||
type: "xxh64",
|
||||
};
|
||||
}
|
||||
|
||||
async function readEncrypted(filename, key, cipherData) {
|
||||
console.log("Reading encrypted file", filename);
|
||||
const readAsBuffer = localforage.supports(localforage.INDEXEDDB);
|
||||
cipherData.cipher = await fs.getItem(filename);
|
||||
if (!cipherData.cipher)
|
||||
@@ -64,5 +66,55 @@ async function readEncrypted(filename, key, cipherData) {
|
||||
: await crypto.decrypt(key, cipherData, cipherData.outputType);
|
||||
}
|
||||
|
||||
const FS = { writeEncrypted, readEncrypted };
|
||||
async function uploadFile(filename, requestOptions) {
|
||||
console.log("Request to upload file", filename, requestOptions);
|
||||
const { url } = requestOptions;
|
||||
|
||||
let cipher = await fs.getItem(filename);
|
||||
if (!cipher) throw new Error(`File not found. Filename: ${filename}`);
|
||||
|
||||
const readAsBuffer = localforage.supports(localforage.INDEXEDDB);
|
||||
if (!readAsBuffer)
|
||||
cipher = Uint8Array.from(window.atob(cipher), (c) => c.charCodeAt(0));
|
||||
|
||||
const response = await axios.request({
|
||||
url: url,
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "",
|
||||
},
|
||||
data: new Blob([cipher.buffer]),
|
||||
onUploadProgress: (ev) => {
|
||||
console.log("Uploading file", filename, ev);
|
||||
},
|
||||
});
|
||||
|
||||
console.log("File uploaded:", filename, response);
|
||||
return isSuccessStatusCode(response.status);
|
||||
}
|
||||
|
||||
async function downloadFile(filename, requestOptions) {
|
||||
const { url, headers } = requestOptions;
|
||||
console.log("Request to download file", filename, url, headers);
|
||||
if (await fs.hasItem(filename)) return true;
|
||||
|
||||
const response = await axios.get(url, {
|
||||
headers: headers,
|
||||
responseType: "blob",
|
||||
onDownloadProgress: (ev) => {
|
||||
console.log("Downloading file", filename, ev);
|
||||
},
|
||||
});
|
||||
console.log("File downloaded", filename, url, response);
|
||||
if (!isSuccessStatusCode(response.status)) return false;
|
||||
const blob = new Blob([response.data]);
|
||||
await fs.setItem(filename, new Uint8Array(await blob.arrayBuffer()));
|
||||
return true;
|
||||
}
|
||||
|
||||
const FS = { writeEncrypted, readEncrypted, uploadFile, downloadFile };
|
||||
export default FS;
|
||||
|
||||
function isSuccessStatusCode(statusCode) {
|
||||
return statusCode >= 200 && statusCode <= 299;
|
||||
}
|
||||
|
||||
@@ -81,12 +81,12 @@ export default class NNCryptoWorker {
|
||||
/**
|
||||
*
|
||||
* @param {{password: string}|{key:string, salt: string}} passwordOrKey - password or derived key
|
||||
* @param {string} data - the plaintext data
|
||||
* @param {string|Uint8Array} data - the plaintext data
|
||||
* @param {string} type
|
||||
*/
|
||||
encryptBinary = (passwordOrKey, data, type = "plain") => {
|
||||
const payload = { type, data };
|
||||
const transferables = type === "buffer" ? [payload.data] : [];
|
||||
const transferables = type === "buffer" ? [payload.data.buffer] : [];
|
||||
return this._communicate(
|
||||
"encryptBinary",
|
||||
{
|
||||
@@ -106,7 +106,7 @@ export default class NNCryptoWorker {
|
||||
cipherData.output = outputType;
|
||||
cipherData.inputType = "uint8array";
|
||||
return this._communicate("decrypt", { passwordOrKey, cipher: cipherData }, [
|
||||
cipherData.cipher,
|
||||
cipherData.cipher.buffer,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user