You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
|`VITE_UPLOAD_CHUNK_SIZE`| none | Upload chunk size in bytes |
132
138
|`VITE_FILEREAD_CHUNK_SIZE`| none | File read chunk size in bytes |
133
139
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
+
134
154
## Releasing
135
155
136
156
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.
Copy file name to clipboardExpand all lines: docs/sdk/js-decryption.md
+13-4Lines changed: 13 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,7 +31,7 @@ Pass `{ uuid }` to `pg.open()`, then call `decrypt()` with `element` (a CSS sele
31
31
32
32
The return type is the union `DecryptResult = DecryptFileResult | DecryptDataResult`. Which variant you get mirrors how the payload reached Cryptify:
33
33
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.
35
35
- Uploaded via `Sealed.upload({ data })` → `DecryptDataResult` with `plaintext` as a `Uint8Array`.
36
36
37
37
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 })`.
62
62
63
63
| Property | Type | Description |
64
64
|----------|------|-------------|
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`|
66
66
|`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
+
:::
69
73
70
74
## Decrypt from raw data
71
75
@@ -105,6 +109,7 @@ Returned from `{ data }` decryption, and from `{ uuid }` when the payload was up
105
109
|`session`|`SessionCallback`| No*| Custom session callback for non-browser environments |
106
110
|`recipient`|`string`| No | Email of the recipient to decrypt for (required if multiple recipients) |
107
111
|`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)) |
108
113
109
114
*Provide either `element` or `session`. If neither is provided, the SDK throws a `DecryptionError`.
110
115
@@ -160,6 +165,8 @@ The full `FriendlySender` type:
160
165
|`attributes`|`Array<{ type, value? }>`| All identity attributes |
161
166
|`raw`|`SenderIdentity`| Raw identity structure for advanced use |
162
167
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
+
163
170
## Error handling
164
171
165
172
Decryption can throw:
@@ -171,6 +178,8 @@ Decryption can throw:
171
178
172
179
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.
173
180
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).
Callers that handle the result must null-check `envelope.attachment` before reading it, since tier 3 envelopes carry no attachment.
144
144
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).
0 commit comments