mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 20:42:43 +00:00
fix(apns): add diagnostic dump on PEM parse failure (v1.4.47.3)
v1.4.47.2 normalisation didn't recover the production PEM. Emit a structured diagnostic on the existing parse-failure branch (counts + sha256_prefix, no secret bytes) so the operator can compare the in-container shape against the source .p8.
This commit is contained in:
1 parent
0be10edc66
commit
d4b8c3bb5a
3 files changed
+47
-3
No files matched your search
@@ -1,5 +1,27 @@
|
||||
# Changelog
|
||||
|
||||
## [1.4.47.3] — 2026-05-22 — APNs PEM diagnostic dump on parse failure
|
||||
|
||||
v1.4.47.2 added defensive PEM normalisation but the production env-var was still rejected at `crypto.createPrivateKey` with `error:1E08010C:DECODER routines::unsupported`. The base64 body itself appears to be corrupted somewhere along the Coolify → docker-compose → `process.env` path; normalising the wrapping cannot recover it.
|
||||
|
||||
This release adds a one-line diagnostic dump on parse failure so the operator can compare the in-container shape against the source `.p8`:
|
||||
|
||||
```
|
||||
APNs key did not parse as PEM: <err> [diag raw_len=… norm_len=…
|
||||
escaped_newlines=… real_newlines=… begin_markers=… end_markers=…
|
||||
base64_chars=… other_chars=… sha256_prefix=…]
|
||||
```
|
||||
|
||||
No secret bytes leave the warning — only character-class counts, structural marker counts, and a 16-char SHA-256 prefix that the operator can compare against `shasum -a 256 AuthKey_*.p8` locally.
|
||||
|
||||
### Changed
|
||||
|
||||
- `src/lib/notifications/senders/apns.ts:loadApnsConfig` — on the existing `crypto.createPrivateKey` failure branch, emit a structured diagnostic warning. Channel disable behaviour unchanged.
|
||||
|
||||
### Risk
|
||||
|
||||
Zero. Behaviour-preserving — only the warning message gets richer when the parse already fails.
|
||||
|
||||
## [1.4.47.2] — 2026-05-22 — APNs JWT signing repair (defensive PEM normalisation)
|
||||
|
||||
Same-day follow-up to v1.4.47.1. Coolify runtime logs surfaced
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "healthlog",
|
||||
"version": "1.4.47.2",
|
||||
"version": "1.4.47.3",
|
||||
"description": "Self-hosted personal-health-tracking PWA with Withings integration, AI insights, and doctor-report PDF export.",
|
||||
"license": "AGPL-3.0-only",
|
||||
"homepage": "https://healthlog.dev",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
* separately — that's what the library is for, and pinning a single
|
||||
* token to the process lifetime would expire ~50 minutes after boot.
|
||||
*/
|
||||
import { createPrivateKey } from "node:crypto";
|
||||
import { createHash, createPrivateKey } from "node:crypto";
|
||||
import { readFileSync } from "node:fs";
|
||||
|
||||
import apn from "@parse/node-apn";
|
||||
@@ -219,7 +219,29 @@ export function loadApnsConfig(): ApnsConfig | null {
|
||||
}
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : "parse_failed";
|
||||
getEvent()?.addWarning(`APNs key did not parse as PEM: ${message}`);
|
||||
// v1.4.47.3 — diagnostic dump on parse failure so operators can
|
||||
// tell whether the env-var arrived in the expected shape.
|
||||
// Logs nothing sensitive: only lengths, character-class counts,
|
||||
// and a SHA-256 prefix of the normalised body. Never the key bytes.
|
||||
const sha256 = createHash("sha256").update(signingKey).digest("hex");
|
||||
const escapedNewlineCount = (inlineKey.match(/\\n/g) || []).length;
|
||||
const realNewlineCount = (signingKey.match(/\n/g) || []).length;
|
||||
const beginCount = (signingKey.match(/-----BEGIN/g) || []).length;
|
||||
const endCount = (signingKey.match(/-----END/g) || []).length;
|
||||
const base64Chars = (signingKey.match(/[A-Za-z0-9+/=]/g) || []).length;
|
||||
const otherChars =
|
||||
signingKey.length -
|
||||
base64Chars -
|
||||
realNewlineCount -
|
||||
(signingKey.match(/[-\s]/g) || []).length;
|
||||
getEvent()?.addWarning(
|
||||
`APNs key did not parse as PEM: ${message} ` +
|
||||
`[diag raw_len=${inlineKey.length} norm_len=${signingKey.length} ` +
|
||||
`escaped_newlines=${escapedNewlineCount} real_newlines=${realNewlineCount} ` +
|
||||
`begin_markers=${beginCount} end_markers=${endCount} ` +
|
||||
`base64_chars=${base64Chars} other_chars=${otherChars} ` +
|
||||
`sha256_prefix=${sha256.slice(0, 16)}]`,
|
||||
);
|
||||
cachedConfig = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user