Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export default withMermaid(defineConfig({
collapsed: false,
items: [
{ text: 'pg-sveltekit', link: '/repos/pg-sveltekit' },
{ text: 'pg-node', link: '/repos/pg-node' },
{ text: 'pg-dotnet', link: '/repos/pg-dotnet' },
{ text: 'pg-manual', link: '/repos/pg-manual' },
],
Expand Down
1 change: 1 addition & 0 deletions docs/repos/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ From the [postguard-examples](https://github.com/encryption4all/postguard-exampl
| Project | Language | Description |
|---|---|---|
| [pg-sveltekit](/repos/pg-sveltekit) | TypeScript | SvelteKit web app using `@e4a/pg-js` |
| [pg-node](/repos/pg-node) | JavaScript | Node.js CLI using `@e4a/pg-js` from a server runtime |
| [pg-dotnet](/repos/pg-dotnet) | C# | .NET console app using `E4A.PostGuard` |
| [pg-manual](/repos/pg-manual) | JavaScript | Browser example using `@e4a/pg-wasm` directly (no SDK) |

Expand Down
79 changes: 79 additions & 0 deletions docs/repos/pg-node.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# pg-node

[GitHub](https://github.com/encryption4all/postguard-examples/tree/main/pg-node) · JavaScript · Node.js Example

A plain Node.js CLI example showing how to use [`@e4a/pg-js`](/repos/postguard-js) from a server runtime. Part of the [postguard-examples](https://github.com/encryption4all/postguard-examples) repository.

Mirrors the [pg-sveltekit](/repos/pg-sveltekit) "Informatierijk notificeren" flow (citizen exact-email recipient + organisation email-domain recipient) as a CLI script.

It shows two modes:

1. **Encrypt and Send**: Encrypts the input files for both recipients, uploads to Cryptify, and asks Cryptify to email each recipient a download link.
2. **Encrypt and Upload**: Same upload, but silent. Cryptify returns a UUID you can distribute through some other channel.

## Prerequisites

- **Node.js 22+**, matching the example's `engines.node`. The SDK itself supports Node 20.3+, Bun, and Deno (see [postguard-js > Server-side usage](/repos/postguard-js#server-side-usage)).
- A PostGuard for Business API key.

## Setup

```bash
cd pg-node
npm install
cp .env.example .env
# edit .env: set at minimum PG_API_KEY
```

Run one of the two modes:

```bash
npm run send # encrypt + upload + ask Cryptify to send mails
npm run upload # encrypt + upload silently, no mails
```

The script prints the resulting `uuid` and the corresponding `/download?uuid=...` URL.

## Configuration

| Variable | Description | Default |
| ----------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------- |
| `PG_API_KEY` | PostGuard for Business API key (`PG-...`) | *(required)* |
| `PG_PKG_URL` | PostGuard PKG server URL | `https://pkg.staging.postguard.eu` |
| `PG_CRYPTIFY_URL` | Cryptify file-sharing URL | `https://storage.staging.postguard.eu` |
| `PG_DOWNLOAD_URL` | PostGuard website used in `/download` URLs | `https://staging.postguard.eu` on staging Cryptify, else `https://postguard.eu` |
| `PG_CITIZEN_EMAIL` | Citizen recipient (exact email match) | `citizen@example.com` |
| `PG_ORGANISATION_EMAIL` | Organisation recipient (matches by domain) | `noreply@example.org` |
| `PG_MESSAGE` | Optional unencrypted body for Cryptify's notify mail | *(empty)* |
| `PG_INPUT_FILES` | Comma-separated file paths to encrypt | two in-memory demo files |

The default `PG_CRYPTIFY_URL` is the staging deployment. Staging Cryptify does not actually deliver notification emails, so `npm run send` succeeds without spamming real inboxes while you integrate. The upload still returns a real UUID and the download URL is usable.

## How it maps to the SDK

The encryption code lives in `src/encryption.mjs`. The send mode passes a `notify` object to opt into Cryptify-sent emails:

```js
const sealed = pg.encrypt({
files,
recipients: [
pg.recipient.email(citizen.email),
pg.recipient.emailDomain(organisation.email),
],
sign: pg.sign.apiKey(apiKey),
onProgress,
signal,
});

const result = await sealed.upload({
notify: {
recipients: true,
message: message || undefined,
language: 'EN',
},
});
```

<small>[Source: encryption.mjs#L13-L40](https://github.com/encryption4all/postguard-examples/blob/0fb7789560595d29d28fcf4222e67dc1ab887c2e/pg-node/src/encryption.mjs#L13-L40)</small>

The upload mode calls `sealed.upload()` with no options. The upload is silent by default; pass `notify` only when you want Cryptify to send the recipient mail. See [JS SDK > Notify options](/sdk/js-encryption#notify-options) for the full shape.
10 changes: 9 additions & 1 deletion docs/repos/postguard-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,19 @@ try {
}
```

## Server-side usage

The SDK runs on browsers, Node.js (20.3+), Bun, and Deno. The lower bound is set by `AbortSignal.any`, listed in `engines.node` of the package.

Encrypt and upload calls work identically across all four runtimes. Decryption with `pg.sign.yivi(...)` and `opened.decrypt({ element })` is browser-only — both render the Yivi QR widget into a DOM element. Calling `pg.sign.yivi(...)` from a server runtime throws `YiviSessionError` upfront before any session starts; pick `pg.sign.apiKey(...)` or `pg.sign.session(...)` instead.

See the [pg-node example](/repos/pg-node) for a runnable Node.js script using `pg.sign.apiKey`.

## Development

### Prerequisites

- Node.js 20+
- Node.js 20.3+ (or Bun / Deno)

### Building

Expand Down
5 changes: 4 additions & 1 deletion docs/sdk/dotnet-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,17 @@ Thrown when an HTTP request to the PKG or Cryptify fails.
|---|---|---|
| `StatusCode` | `int` | HTTP status code |
| `Body` | `string` | Response body |
| `Url` | `string` | Request URL that failed (PKG or Cryptify endpoint) |

```csharp
catch (NetworkException ex)
{
Console.WriteLine($"HTTP {ex.StatusCode}: {ex.Body}");
Console.WriteLine($"HTTP {ex.StatusCode} at {ex.Url}: {ex.Body}");
}
```

The exception message follows the same format: `HTTP {status} at {url}: {body}` (e.g. `HTTP 401 at https://pkg.postguard.eu/v2/irma/sign/key: Unauthorized`). The `Url` property lets callers wrapping this SDK distinguish a PKG failure from a Cryptify failure (and which Cryptify phase) without parsing the message.

## `SealException`

Thrown when the native cryptographic library (`libpg_ffi`) fails during encryption. This typically indicates a problem with the input data or the native library itself.
4 changes: 4 additions & 0 deletions docs/sdk/js-encryption.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ The upload is silent by default. Both recipient and sender mails are opt-in. Pas
| `message` | `string` | `undefined` | Optional unencrypted text included in any mail sent |
| `language` | `'EN' \| 'NL'` | `'EN'` | Notification email template language |

The SDK validates the `notify` shape and throws `TypeError` for common misuse like `{ notify: true }`, a top-level `recipients`, or non-boolean values such as `{ recipients: 'yes' }`. Catch this in tests rather than at runtime.

If `notify` is omitted on the first `sealed.upload()` for a given `PostGuard` instance, the SDK logs a one-time `console.info` reminding you that the upload is silent and how to opt in. Pass `{ recipients: false }` to acknowledge the silent intent and suppress the notice — the validator counts both as explicit shapes.

## Encrypt raw data

For email addons, use `data` instead of `files`. The Thunderbird addon's crypto popup encrypts the full MIME message (body + attachments) as raw bytes, then wraps it in an email envelope:
Expand Down
1 change: 1 addition & 0 deletions docs/sdk/js-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ Thrown when:
- The user declines disclosure in the Yivi app
- The Yivi session times out
- The Yivi session is aborted for any other non-success reason
- `pg.sign.yivi(...)` is called from a non-browser runtime (Node, Bun, Deno). The QR widget needs a DOM, so the call fails fast before any session starts. Use `pg.sign.apiKey(...)` or `pg.sign.session(...)` from a server runtime.

Affects both `pg.encrypt(...).upload()` and `pg.encrypt(...).toBytes()` when `pg.sign.yivi(...)` is used, and `pg.open(...).decrypt(...)` when a Yivi session backs the decryption.

Expand Down
Loading