Home

Awesome

secure-file-transfer

API documentation

Source code

Install

npm i --save secure-file-transfer

secure-file-transfer (SFT) is the easiest solution for securely getting a file from one web browser to another. It works by connecting two people via WebTorrent and transferring files peer-to-peer via WebRTC. Files are encrypted prior to transmission and decrypted upon receipt, so data is never exposed to anyone other than the intended recipient. Files are never sent to a server, and no server setup is needed to use SFT.

SFT is the library that Chitchatter uses to transfer files to connected peers.

Why use secure-file-transfer?

SFT builds on top of WebTorrent and several other excellent JavaScript libraries. It is specially tuned to minimize memory usage, thus enabling the delivery of very large files (as much as your browser can handle).

WebTorrent is a powerful library, but there are a number of important things it doesn't do:

By default, WebTorrent stores torrents in system memory. This is also not suitable for very large files. To work around this, SFT uses idb-chunk-store to stream data directly from the sender's disk to the receiver's and keep memory usage low.

Limitations

SFT has no file size limits. However, since transferred data is cached in IndexedDB via idb-chunk-store (to minimize memory usage and enable larger file transfers), it is subject to browser storage limits.

Example

On one page have, something like this (in TypeScript):

import { fileTransfer } from "secure-file-transfer";

document.body.innerHTML = `
<input type="text" placeholder="Encryption key" />
<input type="file" multiple />
<h1>Magnet URI:</h1>
<p />
`;

const fileInput = document.querySelector('[type="file"]');
const passwordInput = document.querySelector('[type="text"]');
const p = document.querySelector("p");

const handleChange = async (evt: Event) => {
  const password = passwordInput.value;
  const magnetURI = await fileTransfer.offer(evt.target.files, password);
  p.innerText = magnetURI;
};

fileInput?.addEventListener("change", handleChange);

Then on another page, something like this:

import { fileTransfer } from "secure-file-transfer";

document.body.innerHTML = `
<input type="text" placeholder="Encryption key" style="display: block;" />
<textarea placeholder="Magnet URI"></textarea>
<button style="display: block;">Download file(s)</button>
<p></p>
`;

const downloadButton = document.querySelector("button");
const passwordInput = document.querySelector('[type="text"]');
const magnetUriInput = document.querySelector("textarea");
const status = document.querySelector("p");

const handleDownloadClick = async (evt: Event) => {
  status?.innerText = "Downloading...";
  const password = passwordInput.value;
  const magnetUri = magnetUriInput.value;
  await fileTransfer.download(magnetUri, password, { doSave: true });
  status?.innerText = "Done!";
};

downloadButton.addEventListener("click", handleDownloadClick);

If the encryption keys match, the file will be transferred directly from the offerer to the receiver and saved to the local file system (so long as both peers keep their pages open).

Troubleshooting

Files can't be downloaded from peers

SFT uses StreamSaver.js to facilitate large file transfers. Download managers such as FDM are known to interfere with StreamSaver.js, so it is recommended to disable such download managers when using SFT to receive files.

License

MIT.