Skip to content

Commit 8638872

Browse files
docs: weekly update — 2026-06-06 (#114)
* docs: document pg-js 2.0 DecryptFileResult + onDownloadProgress + cause-preserving IdentityMismatchError Sources: - encryption4all/postguard-js#86 (DecryptFileResult shape change, onDownloadProgress) - encryption4all/postguard-js#84 (IdentityMismatchError cause preservation) * docs: clarify createEnvelope tier 2 vs tier 3 upload-failure semantics Source: encryption4all/postguard-js#82 (re-throw on tier 3, console.warn on tier 2) * docs: add Runtime config section for postguard-website APP_CONFIG keys Sources: - encryption4all/postguard-website#244 (STAGING) - encryption4all/postguard-website#247 (GLITCHTIP_DSN) - encryption4all/postguard-website#255 (SITE_URL) * docs: surface private signing attributes on FriendlySender (from encryption4all/postguard-js#89) * docs: document /download trust-confirmation gate (from encryption4all/postguard-website#258) --------- Co-authored-by: dobby-yivi-agent[bot] <275734547+dobby-yivi-agent[bot]@users.noreply.github.com>
1 parent 66678f5 commit 8638872

3 files changed

Lines changed: 42 additions & 4 deletions

File tree

docs/repos/postguard-website.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ if (uuidParam) {
4949

5050
<small>[Source: src/routes/(app)/decrypt/+page.svelte#L86-L106](https://github.com/encryption4all/postguard-website/blob/0398c87d113ab7b9fc518f4eb9aaf7059745d54a/src/routes/%28app%29/decrypt/%2Bpage.svelte#L86-L106)</small>
5151

52+
### Download confirmation gate
53+
54+
Since [encryption4all/postguard-website#258](https://github.com/encryption4all/postguard-website/pull/258), the `/download` page decrypts into in-memory blobs and pauses on a confirmation step before any file is written to disk. The recipient sees the file list and the verified sender, then chooses to keep or discard the files. Declining drops the blobs without writing them; accepting starts the browser downloads. When the sender disclosed nothing beyond their email, the confirmation panel warns that email alone is a weak identity claim, since anyone with control of that mailbox could have signed the message.
55+
5256
## Development
5357

5458
### Quick Start with Docker Compose (recommended)
@@ -123,6 +127,8 @@ adb reverse tcp:8080 tcp:8080 # PostGuard website
123127

124128
## Environment Variables
125129

130+
`VITE_*` variables are read at build time and baked into the bundle.
131+
126132
| Variable | Default | Description |
127133
|---|---|---|
128134
| `VITE_FILEHOST_URL` | `http://localhost:8000` | Cryptify file hosting service URL |
@@ -131,6 +137,20 @@ adb reverse tcp:8080 tcp:8080 # PostGuard website
131137
| `VITE_UPLOAD_CHUNK_SIZE` | none | Upload chunk size in bytes |
132138
| `VITE_FILEREAD_CHUNK_SIZE` | none | File read chunk size in bytes |
133139

140+
## Runtime config
141+
142+
A second tier of flags is read at page load from a global `APP_CONFIG` object served by `static/config.js`. Deployed environments overwrite the file via the Terraform ConfigMap; local Docker Compose uses the in-repo copy. Each key is optional, with a fallback baked into `src/lib/env.ts`.
143+
144+
| Key | Type | Default | Description |
145+
|---|---|---|---|
146+
| `SITE_URL` | string | `https://postguard.eu` | Base URL used by sitemap, RSS, JSON-LD, and the `(app)` routes. Marketing pages are prerendered, so the baked-in fallback is what ships in their static HTML; a runtime override only takes effect on non-prerendered routes such as `/decrypt` and `/fileshare`. Added in [encryption4all/postguard-website#255](https://github.com/encryption4all/postguard-website/pull/255). |
147+
| `BUSINESS_URL` | string | `https://business.postguard.eu` | Link target for the "for Business" entry point. |
148+
| `FF_BUSINESS` | boolean | `false` | Feature flag that controls whether the business entry point is shown. |
149+
| `STAGING` | boolean | `false` | True on staging/dev where cryptify runs with `staging_mode = true` and does not send notification mail. The website renders an in-page preview of the would-be recipient email so developers can grab the download link without trawling cryptify logs. Added in [encryption4all/postguard-website#244](https://github.com/encryption4all/postguard-website/pull/244). |
150+
| `GLITCHTIP_DSN` | string | `""` | DSN for a Sentry-compatible error reporter (PostGuard runs GlitchTip). An empty value disables reporting at module load. The fileshare flow's `CrashReport` panel uses this to POST captured exceptions on user opt-in. Added in [encryption4all/postguard-website#247](https://github.com/encryption4all/postguard-website/pull/247). |
151+
152+
The runtime tier exists because these values change per environment without rebuilding the static bundle. Override them by replacing `config.js` in the served container.
153+
134154
## Releasing
135155

136156
This repository uses [Release-please](https://github.com/googleapis/release-please) for automated versioning. Merging a release PR triggers a multi-architecture Docker image build pushed to GHCR.

docs/sdk/js-decryption.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Pass `{ uuid }` to `pg.open()`, then call `decrypt()` with `element` (a CSS sele
3131

3232
The return type is the union `DecryptResult = DecryptFileResult | DecryptDataResult`. Which variant you get mirrors how the payload reached Cryptify:
3333

34-
- Uploaded via `Sealed.upload({ files })``DecryptFileResult` with `files`, `blob`, and a `download()` helper.
34+
- Uploaded via `Sealed.upload({ files })``DecryptFileResult` with a `files` array of `{ name, blob }` entries, the raw ZIP as `blob`, and a `download()` helper that fans out one browser download per entry.
3535
- Uploaded via `Sealed.upload({ data })``DecryptDataResult` with `plaintext` as a `Uint8Array`.
3636

3737
This keeps the round-trip `pg.encrypt({ data }).upload()``pg.open({ uuid }).decrypt()` symmetric: raw bytes go in, raw bytes come out. Internally, `Sealed.upload({ data })` wraps the bytes as a single-entry zip named `data.bin`; on decrypt the SDK inspects the inner zip's central directory and, when the entries are exactly `['data.bin']`, unwraps that entry and returns `DecryptDataResult`.
@@ -62,10 +62,14 @@ Returned when the payload was uploaded with `Sealed.upload({ files })`.
6262

6363
| Property | Type | Description |
6464
|----------|------|-------------|
65-
| `files` | `string[]` | Filenames inside the ZIP |
65+
| `files` | `Array<{ name: string; blob: Blob }>` | One entry per file inside the ZIP, with the entry's filename and decoded `Blob` |
6666
| `sender` | `FriendlySender \| null` | Verified sender identity with `.email` and `.attributes` |
67-
| `blob` | `Blob` | The decrypted ZIP blob |
68-
| `download` | `(filename?: string) => void` | Trigger a browser download |
67+
| `blob` | `Blob` | The raw decrypted ZIP, as an escape hatch for callers that want to re-upload, hand-process, or offer a single "Download as ZIP" button |
68+
| `download` | `() => void` | Triggers one browser download per entry in `files` |
69+
70+
::: warning Breaking change in v2
71+
Prior to `@e4a/pg-js@2.0.0`, `files` was `string[]` (filenames only) and `download` took an optional `filename` argument that selected a single entry. The new `download()` takes no arguments and fans out per entry; callers that want a single combined download can pipe `blob` through their own anchor. Source: [encryption4all/postguard-js#86](https://github.com/encryption4all/postguard-js/pull/86).
72+
:::
6973

7074
## Decrypt from raw data
7175

@@ -105,6 +109,7 @@ Returned from `{ data }` decryption, and from `{ uuid }` when the payload was up
105109
| `session` | `SessionCallback` | No* | Custom session callback for non-browser environments |
106110
| `recipient` | `string` | No | Email of the recipient to decrypt for (required if multiple recipients) |
107111
| `enableCache` | `boolean` | No | Cache the Yivi JWT so repeated decryptions don't require re-scanning the QR code |
112+
| `onDownloadProgress` | `(pct: number \| undefined) => void` | No | Progress callback for the streaming download+decrypt pipeline. Fires on every chunk with `0–100` when the server set `Content-Length`, or `undefined` when it didn't (consumer should render an indeterminate indicator). Available since `@e4a/pg-js@2.0.0` ([#86](https://github.com/encryption4all/postguard-js/pull/86)) |
108113

109114
*Provide either `element` or `session`. If neither is provided, the SDK throws a `DecryptionError`.
110115

@@ -160,6 +165,8 @@ The full `FriendlySender` type:
160165
| `attributes` | `Array<{ type, value? }>` | All identity attributes |
161166
| `raw` | `SenderIdentity` | Raw identity structure for advanced use |
162167

168+
Since [encryption4all/postguard-js#89](https://github.com/encryption4all/postguard-js/pull/89), `attributes` also carries the attributes the sender signed under their private signing identity (name, mobile, dateofbirth, and so on), not just the public email. Earlier versions discarded the unseal result and surfaced only the email, so recipients saw a single attribute even when the sender had disclosed more. Read the extra attributes from `attributes` to show the recipient exactly who signed the message.
169+
163170
## Error handling
164171

165172
Decryption can throw:
@@ -171,6 +178,8 @@ Decryption can throw:
171178

172179
Catch `IdentityMismatchError` first to show a recipient-mismatch message, then `YiviSessionError` to surface a friendly "session cancelled" message instead of a generic decryption failure, then fall through to a generic error branch for everything else.
173180

181+
Since `@e4a/pg-js@2.0.0`, `IdentityMismatchError` preserves the underlying error on `.cause` when the failure was not a real identity mismatch (network drop during streaming, WASM panic, malformed ciphertext). Inspect `err.cause` when debugging a transient failure that surfaces as a mismatch. An `AbortError` from a caller-supplied `signal` passes through as-is — it is not rewrapped. Source: [encryption4all/postguard-js#84](https://github.com/encryption4all/postguard-js/pull/84).
182+
174183
```ts
175184
import { YiviSessionError, IdentityMismatchError } from '@e4a/pg-js';
176185

docs/sdk/js-email-helpers.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ const envelope = await pg.email.createEnvelope({
142142

143143
Callers that handle the result must null-check `envelope.attachment` before reading it, since tier 3 envelopes carry no attachment.
144144

145+
### Failures during upload
146+
147+
Tier 2 and tier 3 envelopes both attempt a Cryptify upload. Their failure semantics differ:
148+
149+
- **Tier 2** falls back to the local attachment when the upload rejects. The promise resolves and the envelope still contains the `postguard.encrypted` file; the failure is logged via `console.warn` so it isn't silent. The recipient can still decrypt from the attachment.
150+
- **Tier 3** has no local fallback (the attachment is omitted by design), so the original error is re-thrown. `createEnvelope` rejects with the underlying typed error (`NetworkError`, `UploadSessionExpiredError`, or a generic `PostGuardError`) and callers should branch on the same error classes they already use around `Sealed.upload()`.
151+
152+
Prior to `@e4a/pg-js@2.0.0`, a tier 3 upload failure was swallowed and `createEnvelope` returned an envelope with `attachment: null` plus a body whose fallback link pointed at a non-existent Cryptify UUID. Source: [encryption4all/postguard-js#82](https://github.com/encryption4all/postguard-js/pull/82).
153+
145154
### Parameters
146155

147156
| Parameter | Type | Required | Description |

0 commit comments

Comments
 (0)