npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@e4a/pg-wasm

v0.3.2

Published

PostGuard WebAssembly bindings for the browser

Downloads

26

Readme

pg-wasm

This package contains automatically generated WebAssembly bindings to call into the PostGuard Rust library from Javascript or Typescript. This library has been configured to run in a browser via a bundler.

The ReadableStream and WritableStream Web APIs are required. Most notably, WritableStream is not supported on Firefox until version 100, see WritableStream.

If not available, please consider using a polyfill, see web-streams-polyfill.

Usage

See the examples repo for working examples.

Fetching keys

Fetching keys from the PKG (for both decryption/signing) is easiest using the Yivi frontend packages and a custom session field.

// The URL of the PKG.
const PKG_URL = "...";

const KeySorts = {
  Encryption: "key",
  Signing: "sign/key",
};

export async function fetchKey(
  sort,
  keyRequest,
  timestamp = undefined,
  signingKeyRequest = undefined
) {
  const session = {
    url: PKG_URL,
    start: {
      url: (o) => `${o.url}/v2/request/start`,
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(keyRequest),
    },
    result: {
      url: (o, { sessionToken }) => `${o.url}/v2/request/jwt/${sessionToken}`,
      parseResponse: (r) => {
        return r
          .text()
          .then((jwt) =>
            fetch(
              `${PKG_URL}/v2/irma/${sort}${
                timestamp ? "/" + timestamp.toString() : ""
              }`,
              {
                method: sort === KeySorts.Encryption ? "GET" : "POST",
                headers: {
                  Authorization: `Bearer ${jwt}`,
                  "Content-Type": "application/json",
                },
                ...(signingKeyRequest && {
                  body: JSON.stringify({ ...signingKeyRequest }),
                }),
              }
            )
          )
          .then((r) => r.json())
          .then((json) => {
            if (json.status !== "DONE" || json.proofStatus !== "VALID")
              throw new Error("not done and valid");
            return sort === KeySorts.Encryption
              ? json.key
              : { pubSignKey: json.pubSignKey, privSignKey: json.privSignKey };
          })
          .catch((e) => console.log("error: ", e));
      },
    },
  };

  const yivi = new YiviCore({ debugging: false, session });
  yivi.use(YiviClient);
  yivi.use(YiviPopup);
  return yivi.start();
}

Encryption

// Load the WASM module.
const { sealStream } = await import("@e4a/pg-wasm");

// Retrieve the public key from PKG API:
const resp = await fetch(`${url}/v2/parameters`);
const pk = await resp.json().then((r) => r.publicKey);

// We provide the policies which we want to use for encryption.
const policy = {
  Bob: {
    ts: Math.round(Date.now() / 1000),
    con: [{ t: "irma-demo.sidn-pbdf.email.email", v: "[email protected]" }],
  },
};

// We provide the policies which we want to sign with.

// This policy is visible to everyone.
const pubSignId = [
  { t: "irma-demo.gemeente.personalData.fullname", v: "Alice" },
];

// This policy is only visible to recipients.
const privSignId = [{ t: "irma-demo.gemeente.personalData.bsn", v: "1234" }];

// We retrieve keys for these policies.
let { pubSignKey, privSignKey } = await fetchKey(
  KeySorts.Signing,
  { con: [...pubSignId, ...privSignId] },
  undefined,
  { pubSignId, privSignId }
);

const sealOptions = {
  policy,
  pubSignKey,
  privSignKey,
};

// The following call reads data from a `ReadableStream` and seals it into `WritableStream`.
// Make sure that only chunks of type `Uint8Array` are enqueued to `readable`.
await sealStream(pk, sealOptions, readable, writable);

Decryption

// Load the WASM module.
const { StreamUnsealer } = await import("@e4a/pg-wasm");

// Retrieve to global verification key.
const vk = await fetch(`${PKG_URL}/v2/sign/parameters`)
  .then((r) => r.json())
  .then((j) => j.publicKey);

// Start reading from the ReadableStream. This will read
// the metadata up until the actual payload. The stream is still locked.
const unsealer = await StreamUnsealer.new(readable, vk);

// Retrieve the recipients (and their respective policies) from the header.
const recipients = unsealer.inspect_header();

// In this case it will yield:
// {
//  'Bob': {                                              // recipient identifier
//    ts: 1643634276,                                     // timestamp
//    con: [                                              // conjunction of attributes
//      { t: "irma-demo.sidn-pbdf.email.email", v: "" },  // type/value pairs
//    ],
//  },
// }

// The disclosed values have to match with the values used for encryption.
// Note that we do not include a timestamp here.
const keyRequest = {
  con: [{ t: "irma-demo.sidn-pbdf.email.email", v: "Bob" }],
};

const timestamp = recipients.get("Bob").ts;
const usk = await fetchKey(KeySorts.Encryption, keyRequest, timestamp);

// Unseal the contents, writing the plaintext to a `WritableStream`.
let sender = await unsealer.unseal("Bob", usk, writable);

// console.log(sender) will give the policy that was used to sign:
// {
//   "public": {
//     "ts": 1680531126,
//     "con": [
//       {
//         "t": "irma-demo.gemeente.personalData.fullname",
//         "v": "Alice"
//       }
//     ]
//   },
//   "private": {
//     "ts": 1680531130,
//     "con": [
//       {
//         "t": "irma-demo.gemeente.personalData.bsn",
//         "v": "1234"
//       }
//     ]
//   }
// }

Encrypting Uint8Array

Encrypting and decrypting Uint8Array works similar as the example above. The WASM module also exports seal and Unsealer, which can be used for this. The function seal returns a new Uint8Array. The Unsealer.unseal method returns an array [plain, policy], where plain is a Uint8Array containing the plaintext and policy is an object containing the sender's signing policy.

Leveraging Web Workers

Since ReadableStream and WritableStream are transferable, it is advised to perform the sealing and unsealing off the main thread, e.g., in a Web Worker. Comlink can be a useful library to communicate between threads.

Building the package from the crate

Prerequisites

Make sure the latest version of wasm-pack is installed:

cargo install --git https://github.com/rustwasm/wasm-pack.git

Building

To build the bindings package, run:

wasm-pack build --release -d pkg/ --out-name index --scope e4a --target bundler

Note that this includes a scope.

Testings

To test the bindings package, run:

wasm-pack test --chrome --headless

Publishing (on npm)

The following command publishes the wasm module as a package on npm:

wasm-pack publish