diff --git a/package-lock.json b/package-lock.json index 7b12ba9..25b1999 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@shadow-drive/sdk", - "version": "5.1.0", + "version": "5.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@shadow-drive/sdk", - "version": "5.1.0", + "version": "5.1.1", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@coral-xyz/anchor": "^0.27.0", diff --git a/package.json b/package.json index 8eb04bb..d9a7719 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@shadow-drive/sdk", - "version": "5.1.1", + "version": "6.0.0", "description": "Interfaces for GenesysGo ShadowDrive", "main": "./dist/index.js", "module": "./dist/index.js", diff --git a/src/methods/edit-file.ts b/src/methods/edit-file.ts index 58c1dbf..a5a0f33 100644 --- a/src/methods/edit-file.ts +++ b/src/methods/edit-file.ts @@ -1,32 +1,27 @@ import { web3 } from "@coral-xyz/anchor"; import { isBrowser, SHDW_DRIVE_ENDPOINT } from "../utils/common"; import crypto from "crypto"; -import { ShadowFile, ShadowEditResponse } from "../types"; import fetch from "cross-fetch"; +import { ShadowFile, ShadowUploadResponse } from "../types"; import NodeFormData from "form-data"; import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; import nacl from "tweetnacl"; -import { UserInfo } from "../types/accounts"; /** * - * @param {web3.PublicKey} key - Publickey of Storage Account - * @param {string} url - URL of existing file + * @param {web3.PublicKey} key - Publickey of Storage Account. * @param {File | ShadowFile} data - File or ShadowFile object, file extensions should be included in the name property of ShadowFiles. - * @returns {ShadowEditResponse} - File location + * @returns {ShadowUploadResponse} File location and transaction signature. */ - export default async function editFile( - key: web3.PublicKey, - url: string, + key: web3.PublicKey, data: File | ShadowFile -): Promise { +): Promise { let fileErrors = []; - let fileBuffer: Buffer | ArrayBuffer; + let fileBuffer: Buffer; let form; let file; if (!isBrowser) { - console.log(`not browser`); data = data as ShadowFile; form = new NodeFormData(); file = data.file; @@ -41,70 +36,60 @@ export default async function editFile( if (fileBuffer.byteLength > 1_073_741_824 * 1) { fileErrors.push({ - file: file, + file: data.name, erorr: "Exceeds the 1GB limit.", }); } + /** + * + * Users must remember to include the file extension when uploading from Node. + * + */ + // if (!isBrowser && data.name.lastIndexOf(".") == -1) { + // fileErrors.push({ + // file: data.name, + // error: "File extension must be included.", + // }); + // } if (fileErrors.length) { return Promise.reject(fileErrors); } - const userInfoAccount = await UserInfo.fetch(this.connection, this.userInfo); - if (userInfoAccount === null) { + if (!this.userInfo) { return Promise.reject( - new Error( - "You have not created a storage account on Shadow Drive yet. Please see the 'create-storage-account' command to get started." - ) + "You have not created a storage account on Shadow Drive yet. Please see the 'create-storage-account' command to get started." ); } - let existingFileData, fileDataResponse; - try { - existingFileData = await fetch(`${SHDW_DRIVE_ENDPOINT}/get-object-data`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - location: url, - }), - }); - fileDataResponse = await existingFileData.json(); - } catch (e) { - return Promise.reject(new Error(e.message)); - } - const fileOwnerOnChain = new web3.PublicKey( - fileDataResponse.file_data["owner-account-pubkey"] - ); - if (!fileOwnerOnChain.equals(this.wallet.publicKey)) { - return Promise.reject(new Error("Permission denied: Not file owner")); - } const fileHashSum = crypto.createHash("sha256"); + const fileNameHashSum = crypto.createHash("sha256"); fileHashSum.update( Buffer.isBuffer(fileBuffer) ? fileBuffer : Buffer.from(fileBuffer) ); - const fileHash = fileHashSum.digest("hex"); + fileNameHashSum.update(data.name); + const fileNameHash = fileNameHashSum.digest("hex"); try { - const msg = Buffer.from( - `Shadow Drive Signed Message:\n StorageAccount: ${key}\nFile to edit: ${data.name}\nNew file hash: ${fileHash}` + const msg = new TextEncoder().encode( + `Shadow Drive Signed Message:\nStorage Account: ${key}\nUpload files with hash: ${fileNameHash}` ); - let msgSig; + let msgSig: Uint8Array; if (!this.wallet.signMessage) { msgSig = nacl.sign.detached(msg, this.wallet.payer.secretKey); } else { msgSig = await this.wallet.signMessage(msg); } const encodedMsg = bs58.encode(msgSig); + form.append("fileNames", data.name); form.append("message", encodedMsg); - form.append("signer", this.wallet.publicKey.toString()); form.append("storage_account", key.toString()); - form.append("url", url); + form.append("signer", this.wallet.publicKey.toString()); + form.append("overwrite", "true"); } catch (e) { return Promise.reject(new Error(e.message)); } try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 7200000); - const uploadResponse = await fetch(`${SHDW_DRIVE_ENDPOINT}/edit`, { + const uploadResponse = await fetch(`${SHDW_DRIVE_ENDPOINT}/upload`, { method: "POST", //@ts-ignore body: form, @@ -116,7 +101,7 @@ export default async function editFile( Server response status message: ${(await uploadResponse.json()).error}`) ); } - const responseJson: ShadowEditResponse = await uploadResponse.json(); + const responseJson = await uploadResponse.json(); return Promise.resolve(responseJson); } catch (e) { return Promise.reject(new Error(e.message)); diff --git a/src/methods/upload-file.ts b/src/methods/upload-file.ts index 704923f..2c20594 100644 --- a/src/methods/upload-file.ts +++ b/src/methods/upload-file.ts @@ -10,11 +10,13 @@ import nacl from "tweetnacl"; * * @param {web3.PublicKey} key - Publickey of Storage Account. * @param {File | ShadowFile} data - File or ShadowFile object, file extensions should be included in the name property of ShadowFiles. + * @param {Boolean} overwrite - If true, overwrites if existing. Default is false. * @returns {ShadowUploadResponse} File location and transaction signature. */ export default async function uploadFile( key: web3.PublicKey, - data: File | ShadowFile + data: File | ShadowFile, + overwrite: Boolean = false ): Promise { let fileErrors = []; let fileBuffer: Buffer; @@ -82,6 +84,9 @@ export default async function uploadFile( form.append("message", encodedMsg); form.append("storage_account", key.toString()); form.append("signer", this.wallet.publicKey.toString()); + if(overwrite) { + form.append("overwrite", "true"); + } } catch (e) { return Promise.reject(new Error(e.message)); } diff --git a/src/methods/upload-multiple-files.ts b/src/methods/upload-multiple-files.ts index c955edc..9903fdd 100644 --- a/src/methods/upload-multiple-files.ts +++ b/src/methods/upload-multiple-files.ts @@ -22,6 +22,7 @@ interface FileData { * @param {web3.PublicKey} key - Storage account PublicKey to upload the files to. * @param {FileList | ShadowFile[]} data[] - Array of Files or ShadowFile objects to be uploaded * @param {Number} concurrent - Number of files to concurrently upload. Default: 3 + * @param {Boolean} overwrite - If true, overwrites if existing. Default is false. * @param {Function} callback - Callback function for every batch of files uploaded. A number will be passed into the callback like `callback(num)` indicating the number of files that were confirmed in that specific batch. * @returns {ShadowBatchUploadResponse[]} - File names, locations and transaction signatures for uploaded files. */ @@ -30,7 +31,8 @@ export default async function uploadMultipleFiles( key: web3.PublicKey, data: FileList | ShadowFile[], concurrent = 3, - callback?: Function + overwrite: Boolean = false, + callback?: Function, ): Promise { let fileData: Array = []; const fileErrors: Array = []; @@ -218,6 +220,9 @@ export default async function uploadMultipleFiles( fd.append("storage_account", key.toString()); fd.append("signer", this.wallet.publicKey.toString()); fd.append("fileNames", allFileNames.toString()); + if (overwrite) { + fd.append("overwrite", "true"); + } const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 7200000); const response = await fetch(`${SHDW_DRIVE_ENDPOINT}/upload`, {