Skip to content
 
 

Repository files navigation

Release

  1. Install and authenticate github command line tools
brew install gh
  1. Run npm run release command and follow instruction

USAGE EXAMPLE

Example of 'callback' & 'handlers' parameters

The 'callback' and 'handlers' parameters should always go together. Also, you cannot accept 'type' parameter of 'callback' function if it doesn't exist in 'handlers'.

export const encodeFileData = {
  callbacks: {
    onStart: encryptExistingFileCallback,
    onSuccess: updateFilePropertyCallback,
    onError: catchErrorCallback,
    onProgress: updateProgressCallback,
  },
  handlers: ['onStart', 'onSuccess', 'onError', 'onProgress'],
};

const { handlers, callbacks } = encodeFileData; // use 'handlers' as parameter

const callback = ({ type, params }) => {
  // use 'callback' as parameter
  if (handlers.includes(type)) {
    callbacks[type]({ ...params, dispatch });
  } else {
    console.error(`Handler "${type}" isn't provided`);
  }
};
  1. onStart - used to indicate that action (uploading/encoding/downloading) is started;
  2. onSuccess - used at the end of execution if no errors appeared and function completed successfully;
  3. onError - used to indicate that some error is happened;
  4. onProgress - used to show progress updating after each successful iteration;

Download file

import { downloadFile } from 'gdgateway-client/lib/es5';

const blob = await downloadFile({
    file,
    oneTimeToken,
    endpoint,
    isEncrypted,
    key,
    signal
    callback,
    handlers
})
  1. Inside browser returns a file blob to be downloaded, else returns stream

Accepts:

  1. currentFile - file to be downloaded,
  2. oneTimeToken - token from /generate/token request
  3. endpoint - endpoint from /generate/token request
  4. isEncrypted - boolean flag
  5. key - a key got from getEncryptedFileKey function and used for file decryption or null is file is unencrypted
  6. signal - AbortController's signal is used to cancel file uploading process
  7. callback - callbacks that are responsible for UI updating; accepts 'type' and 'params' parameters;
  8. handlers - an array with all possible handlers of callback function (should include 'type' param of callback function);

Upload unencrypted file

import { uploadFile } from 'gdgateway-client/lib/es5';

// How to create custom file object using node
class CustomFile {
  constructor(size, stream, filename, mimeType, fileFolderId) {
    this.stream = () => stream;
    this.name = filename;
    this.type = mimeType;
    this.folderId = fileFolderId;
    this.size = size;
    this.upload_id = `${filename}_${size}_${fileFolderId}`;
  }
}

const filePath = './src/file-from-node.png'; // path to your file
const filename = 'file-from-node.png'; // name-of-your-file.[extension]
const mimeType = 'image/png'; // mime of your file
const fileFolderId = '';
const { size } = await fs.promises.stat(filePath);

const stream = fs.createReadStream(filePath);

const customFile = new CustomFile(
  size,
  stream,
  filename,
  mimeType,
  fileFolderId
);

await uploadFile({
  file: customFile,
  oneTimeToken,
  gateway,
  callback,
  handlers,
  progress,
  totalSize,
  startedAt,
});
  1. Returns response from the /chunked/uploadChunk request - the whole information about the file

For now there is issue with using node environment (for files with size > 1mb): despite of the fact that we send all chunks, later we get only half of them (for preview/downloading);

Accepts:

  1. file - current file that is supposed to be uploaded; (if node environment and need to send stream - file object should have stream: () => 'ReadableStream with data')
  2. oneTimeToken - token from /generate/token request
  3. gateway - endpoint from /generate/token request (GatewayType)
  4. callback - callbacks that are responsible for UI updating; accepts 'type' and 'params' parameters;
  5. handlers - an array with all possible handlers of callback function (should include 'type' param of callback function);
  6. progress - previous uploaded file's size in bytes - required only for folder uploading;
  7. totalSize - total size of the folder - required only for folder uploading;
  8. startedAt - Date.now() - required only for folder uploading;

Upload encrypted file

import { uploadFile } from 'gdgateway-client/lib/es5';

// getOneTimeToken example: request for endpoint and token
const getOneTimeToken = ({ filesize = '', filename = '' }) => {
  const url = '/api/user/generate/token';
  return authRequest.post(url, { filesize, filename });
};

// How to create custom file object using node
class CustomFile {
  constructor(size, stream, filename, mimeType, fileFolderId) {
    this.stream = () => stream;
    this.name = filename;
    this.type = mimeType;
    this.folderId = fileFolderId;
    this.size = size;
    this.upload_id = `${filename}_${size}_${fileFolderId}`;
  }
}

const filePath = './src/file-from-node.png'; // path to your file
const filename = 'file-from-node.png'; // name-of-your-file.[extension]
const mimeType = 'image/png'; // mime of your file
const fileFolderId = '';
const { size } = await fs.promises.stat(filePath);

const stream = fs.createReadStream(filePath);

const customFile = new CustomFile(
  size,
  stream,
  filename,
  mimeType,
  fileFolderId
);

await uploadFile({
  file: customFile,
  oneTimeToken,
  endpoint,
  callback,
  handlers,
  key,
  progress,
  totalSize,
  startedAt,
});
  1. Returns response from the /chunked/uploadChunk request - the whole information about the file

Accepts:

  1. file - current file that is supposed to be encrypted and uploaded
  2. oneTimeToken - token from /generate/token request
  3. endpoint - endpoint from /generate/token request
  4. callback - callbacks that are responsible for UI updating; accepts 'type' and 'params' parameters;
  5. handlers - an array with all possible handlers of callback function (should include 'type' param of callback function);
  6. key - Crypto Key for file encryption;
  7. progress - previous uploaded file's size in bytes - required only for folder uploading;
  8. totalSize - total size of the folder (in bytes) - required only for folder uploading;
  9. startedAt - Date.now() - required only for folder uploading;

Cancel file uploading

import { cancelingUpload } from 'gdgateway-client/lib/es5';

cancelingUpload(file.uploadId);

This will cancel current chunk uploading.

Accepts:

  1. uploadId - file's upload id is necessary for canceling chunk upload;

Encrypt already uploaded file

import { encodeExistingFile } from 'gdgateway-client/lib/es5';

await encodeExistingFile({
  file,
  oneTimeToken,
  endpoint,
  downloadToken,
  downloadEndpoint,
  callback,
  handlers,
  key,
});
  1. Encrypts existing file and updates isClientsideEncrypted property of current file

Accepts:

  1. file - current file that is supposed to be encrypted and updated
  2. oneTimeToken - OOT for swapping chunks on /chunked/swap/{slug}; (getOneTimeToken)
  3. endpoint - endpoint for swapping chunks on /chunked/swap/{slug}; (getOneTimeToken)
  4. downloadToken - OOT for downloading previous unencrypted file; (getDownloadOOT)
  5. downloadEndpoint - endpoint for downloading previous unencrypted file; (getDownloadOOT)
  6. callback - callbacks that are responsible for UI updating; accepts 'type' and 'params' parameters;
  7. handlers - all possible handlers of callback functions (should include 'type' of callback function);
  8. key - Crypto Key for file encryption

Decrypt chunk

import * as Base64 from 'base64-js';
import { decryptChunk } from 'gdgateway-client/lib/es5';
import { getCrypto } from 'gdgateway-client/lib/es5/utils/getCrypto';

await decryptChunk({ chunk, iv, key });
  1. Return decrypted chunk if correct key is provided

Accepts:

  1. chunk - encrypted arraybuffer chunk of the file
  2. iv - const crypto = getCrypto(); const iv: Uint8Array = crypto.getRandomValues(new Uint8Array(12)); const ivBase64 = Base64.fromByteArray(iv) - this is hat should be used as iv; we convert is to base64 and pass it as headers when send encrypted chunk to backend; when we need to decrypt chunk we get same iv from the information about the file (the iv when we encrypt a chunk should be same as we decrypt this chunk).
  3. key - When you encrypt a chunk, you should generate and export the key (also we save it(keyBase64) to backend) const key = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]) const buffer = await crypto.subtle.exportKey("raw", key); const keyBase64 = convertArrayBufferToBase64(buffer); - this is what should be used as key; the key we use to encrypt file should be the same key we use when we decrypt this file;

Encrypt chunk

import * as Base64 from 'base64-js';
import { encryptChunk } from 'gdgateway-client/lib/es5';
import { getCrypto } from 'gdgateway-client/lib/es5/utils/getCrypto';

await encryptChunk({ chunk, iv, key });
  1. Return encrypted chunk if correct parameters are provided

Accepts:

  1. chunk - simple arraybuffer chunk of the file
  2. iv - const crypto = getCrypto(); const iv: Uint8Array = crypto.getRandomValues(new Uint8Array(12)); - this is what should be used as iv; the same iv should be used when you will need to decrypt this chunk later;
  3. key - When you encrypt a chunk, you should generate and export the key (also we save it(keyBase64) to backend) const key = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]) - generated key should be used as key parameter const buffer = await crypto.subtle.exportKey("raw", key); const keyBase64 = convertArrayBufferToBase64(buffer); - this is what should be used as activationKey for future decrypting;

Chunk file

import { chunkFile } from 'gdgateway-client/lib/es5';

File should be an object with all needed information

const arrayBuffer = await file.arrayBuffer();
const chunks = chunkFile({arrayBuffer});

The chunkFile function returns an array of file chunks (each chunk is arraybuffer like and has 1mb size; only the last chunk can be smaller).

Count chunks

import { countChunks } from 'gdgateway-client/lib/es5';

The 'file' should be an object with all needed information; you should get this information from backend;

const { slug } = file;

await countChunks({
  endpoint,
  oneTimeToken,
  slug,
  controller,
});
  1. The countChunk function returns the {count: 3, end: 4819} - 'count' is quantity of chunks and 'end' is size of the last chunk.

Accepts:

  1. endpoint - endpoint from /generate/token request
  2. oneTimeToken - token from /generate/token request
  3. slug - slug we can get from the full information about the file
  4. controller - AbortController for request cancellation

Download chunk

import { downloadChunk } from 'gdgateway-client/lib/es5';

await downloadChunk = async ({
  index,
  sha3_hash,
  oneTimeToken,
  signal,
  endpoint,
  file,
  startTime,
  totalProgress,
  callback,
  handlers,
})
  1. The downloadChunk function returns arraybuffer chunk.

Accepts:

  1. index - index of chunk to be downloaded; quantity of all chunks we get from countChunks function
  2. sha3_hash - should be null if file is unencrypted; if file is encrypted we get sha3_hash from full information about the file (file.entry_clientside_key.sha3_hash)
  3. oneTimeToken - token from /generate/token request
  4. signal - AbortController's signal for request cancellation
  5. endpoint - endpoint from /generate/token request
  6. file - current file that is supposed to be uploaded
  7. startTime - Date.now(), required to calculate how much time the file upload takes
  8. totalProgress - used to update and calculate progress;
  9. callback - callbacks that are responsible for UI updating; accepts 'type' and 'params' parameters;
  10. handlers - all possible handlers of callback functions (should include 'type' of callback function);

Save blob and download url

import { saveBlob } from 'gdgateway-client/lib/es5';

saveBlob({ blob, name: file?.name });
  1. Simulate user click, revoke url and download it. Used together with downloadFile function;

Accepts:

  1. blob - blob data we get from downloadFile function (/chunked/downloadChunk api)
  2. name - the name of the file to be downloaded

Send chunk

import { sendChunk } from 'gdgateway-client/lib/es5';

await sendChunk({
  chunk,
  index,
  file,
  startTime,
  oneTimeToken,
  endpoint,
  iv,
  clientsideKeySha3Hash,
  totalProgress,
  callback,
  handlers,
  signal,
  totalSize,
});
  1. If it is the last chunk returns the whole information about the file, else returns { success: true }

Accepts:

  1. chunk - arraybuffer chunk to be send
  2. index - current index chunk (get array of chunks from chunkFile function)
  3. file - current file that is supposed to be uploaded
  4. startTime - Date.now(), required to calculate how much time the file upload takes
  5. oneTimeToken - token from /generate/token request
  6. endpoint - endpoint from /generate/token request
  7. iv - should be null if file is unencrypted; if file is encrypted we get generate iv using crypto object import { getCrypto } from 'gdgateway-client/lib/es5/utils/getCrypto'; const crypto = getCrypto(); const iv = crypto.getRandomValues(new Uint8Array(12));
  8. clientsideKeySha3Hash - should be null if file is unencrypted; if file is encrypted we get generate clientsideKeySha3Hash using node-forge const fileKey = forge.random.getBytesSync(32); const md = forge.md.sha512.create(); md.update(fileKey); const clientsideKeySha3Hash = md.digest().toHex();
  9. totalProgress - used to update and calculate progress;
  10. callback - callbacks that are responsible for UI updating; accepts 'type' and 'params' parameters;
  11. handlers - all possible handlers of callback functions (should include 'type' of callback function);
  12. signal - AbortController's signal is used to cancel file uploading process;
  13. totalSize - total size of the folder (in bytes) - required only for folder uploading;

Swap chunk (make simple chunk to be encrypted and send it to server)

import { swapChunk } from 'gdgateway-client/lib/es5';

await swapChunk({
  file,
  endpoint,
  base64iv,
  clientsideKeySha3Hash,
  index,
  oneTimeToken,
  encryptedChunk,
  arrayBuffer,
  startTime,
  totalProgress,
  callback,
  handlers,
});
  1. If it is the last chunk returns the whole information about the file, else returns { success: true }

Accepts:

  1. file - current file that is supposed to be swapped
  2. endpoint - endpoint from /generate/token request
  3. base64iv - get generated iv using crypto object and convert it to base64 import { getCrypto } from 'gdgateway-client/lib/es5/utils/getCrypto'; const crypto = getCrypto(); const iv = crypto.getRandomValues(new Uint8Array(12)); const base64iv = Base64.fromByteArray(this.iv);
  4. clientsideKeySha3Hash - should be null if file is unencrypted; if file is encrypted we get generate clientsideKeySha3Hash using node-forge const fileKey = forge.random.getBytesSync(32); const md = forge.md.sha512.create(); md.update(fileKey); const clientsideKeySha3Hash = md.digest().toHex();
  5. index - current index chunk (get array of chunks from chunkFile function)
  6. oneTimeToken - token from /generate/token request
  7. encryptedChunk - encrypted arraybuffer chunk to be swapped
  8. fileSize - the whole file's size
  9. startTime - Date.now(), required to calculate how much time the file upload takes
  10. totalProgress - used to update and calculate progress
  11. callback - callbacks that are responsible for UI updating; accepts 'type' and 'params' parameters;
  12. handlers - all possible handlers of callback functions (should include 'type' of callback function);

Get user's RSA keys

import { getUserRSAKeys } from 'gdgateway-client/lib/es5';

await getUserRSAKeys({ signer });
  1. Returns generated key pair using node-forge
Example of 'signer':

import { ethers } from 'ethers';

const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();

Convert public key to pem

  1. Returns public key in pem format using node-forge
const keys = await getUserRSAKeys(signer);
const public_key = publicKeyToPem({ publicKey: keys.publicKey });

Accepts:

  1. publicKey - generated public key using getUserRSAKeys function

How to generate and save thumbnails from node

  import { getThumbnailImage, getThumbnailVideo } from 'gdgateway-client/lib/es5';

  // ..upload file and get response (you need file's slug from the response)

  const {
    data: {
      user_token: { token: token },
      endpoint,
    },
  } = await getOneTimeToken({
    filename: file.name,
    filesize: file.size,
  });

  // NODE EXAMPLE
  const sharp = require("sharp");

  const { size } = await fs.promises.stat(filename);
  const filename = "./src/video.mp4";
  const mimeType = "video/mp4";
  const folderId = "";
  const uploadId = `${filename}_${size}_${folderId}`;

  const file = new LocalFileStream(size, filename, mimeType, folderId, uploadId);

  const quality = 3; // 1 to 10 number where 1 is 10% quality and 10 is 100%;

  if (file.type.startsWith("image")) {
    await getThumbnailImage({ path: filename, file, quality: 3, token, endpoint, slug, sharp });
  } else if (file.type.startsWith("video")) {
    const ffmpegPath = require("@ffmpeg-installer/ffmpeg").path;
    const ffmpeg = require("fluent-ffmpeg");

    ffmpeg.setFfmpegPath(ffmpegPath);

    const currentPath = process.cwd();
    const ffmpegCommand = ffmpeg(`${currentPath}/${filename}`);

    await getThumbnailVideo({
        file,
        path: filename,
        ffmpegCommand,
        quality: 3,
        token,
        endpoint,
        slug,
        sharp
    });
  }

  // BROWSER EXAMPLE
  const file = {...} // file object created by browser
  const quality = 3; // 1 to 10 number where 1 is 10% quality and 10 is 100%;

  if (file.type.startsWith('image')) {
    await getThumbnailImage({ file, quality, token, endpoint, slug });
  } else if (file.type.startsWith('video')) {
    await getThumbnailVideo({ file, quality, token, endpoint, slug });
  }

About

Ghost Drive Protocol - Client Gateway: secure client-side bridge to IPFS streaming/storage with DRIVE token and DAO-369 governance.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages