Documentation
Client SDK
Transfer

Secrecy transfer

A Secrecy transfer sends a file to someone who is not a Secrecy user. Unlike the sharing of files and folders, which binds the data to the public key of an existing Secrecy user, a transfer produces a public link that anyone holding the URL can open — the recipient needs no account.

Public does not mean readable. The data behind a transfer is always encrypted in the browser before being uploaded, and the key never leaves the device in clear. What the server stores is an encrypted blob it cannot read. To open the link, the recipient needs the URL and the password, which you deliver out of band — Secrecy never transmits it for you.

How a transfer works

A transfer is made of two objects. The data is the encrypted payload, created by secrecyClient.cloud.uploadData, which returns the data id and a sharing object holding the password and the encrypted data key. The link is then created from that data id with secrecyClient.cloud.createPublicDataLink, and carries a slug — the public part of the URL — a name and an optional expireAt date.

The receiving side needs neither a client nor an account: the standalone downloadDataFromLink function takes the slug, the key and the password, downloads the blob and decrypts it locally.

Managing transfers

A transfer is revocable. Setting an expireAt date makes its link stop working on its own, and that date can be changed at any time with secrecyClient.cloud.updatePublicDataLink. To cut access immediately, secrecyClient.cloud.deletePublicDataLink destroys the link while leaving the underlying data untouched. Several links can point to the same data, and secrecyClient.cloud.getPublicDataLinks lists them.


From a file to a transfer link

Creating a link is a two steps flow. First the file is encrypted and uploaded with secrecyClient.cloud.uploadData, which returns the data id and its sharing credentials. Then a public link is created from that id with secrecyClient.cloud.createPublicDataLink.
What you hand over to the recipient is the slug of the link, the encrypted data key and the password.

The data behind a link is always encrypted. The password is returned once by uploadData and is never stored in clear on the server — if you lose it, the data cannot be recovered.

share.ts
const createLinkForFile = async (file: File) => {
  // First we need to check if the secrecyClient is available
  if (!secrecyClient) {
    return null;
  }
 
  try {
    // 1 - the file is encrypted on the device before being uploaded
    const data = await secrecyClient.cloud.uploadData({
      data: file,
      storageType: 's3',
      encrypted: true,
    });
 
    // 2 - the public link is created from the uploaded data
    const link = await secrecyClient.cloud.createPublicDataLink({
      dataId: data.id,
      name: file.name,
      // null means the link never expires
      expireAt: null,
    });
 
    // the slug is the public part of the url, the sharing part is the secret
    return { slug: link.slug, sharing: data.sharing };
  } catch (error) {
    console.error(error);
    return null;
  }
};

Only the two calls the flow needs are shown here — every parameter of the link creation, including the optional slug and the rules on expireAt, is described on create a public link.


Get a link

The secrecyClient.cloud.getPublicDataLink method retrieves a single link by its id — not by its slug. It returns the link with its name, slug, expireAt and the dataId it points at.

share.ts
const getLink = async (id: string) => {
  // First we need to check if the secrecyClient is available
  if (!secrecyClient) {
    return null;
  }
 
  try {
    // Get the link by id
    const link = await secrecyClient.cloud.getPublicDataLink({ id });
 
    return link;
  } catch (error) {
    console.error(error);
    return null;
  }
};

List the links of a data

The secrecyClient.cloud.getPublicDataLinks method returns all the links created by the current user. Pass a dataIds array to restrict the result to the links pointing at these data — useful because several links can target the same data.

share.ts
const getLinksOfData = async (dataIds?: string[]) => {
  // First we need to check if the secrecyClient is available
  if (!secrecyClient) {
    return null;
  }
 
  try {
    // Without dataIds, all the links of the user are returned
    const links = await secrecyClient.cloud.getPublicDataLinks({ dataIds });
 
    return links;
  } catch (error) {
    console.error(error);
    return null;
  }
};

Update a link

The secrecyClient.cloud.updatePublicDataLink method edits an existing link. Only the id is required, every other property is optional: name to rename it, slug to change its public URL, and expireAt to schedule — or cancel, by passing null — its expiration.

share.ts
const updateLink = async ({
  id,
  name,
  expireAt,
}: {
  id: string;
  name?: string;
  expireAt?: Date | null;
}) => {
  // First we need to check if the secrecyClient is available
  if (!secrecyClient) {
    return null;
  }
 
  try {
    // Only the id is required, the other properties are optional
    const link = await secrecyClient.cloud.updatePublicDataLink({
      id,
      name,
      expireAt,
    });
 
    return link;
  } catch (error) {
    console.error(error);
    return null;
  }
};

Changing the slug breaks the URLs already shared: the previous slug stops resolving as soon as the update succeeds.