Skip to content

Commit 8330a06

Browse files
committed
[runtime] accept base64url keys and force JSON error responses
Why: runtime signing tests were failing because base64url-encoded key material and ENS TXT values were not decoded reliably, causing signer fallback and HTML Express error pages. Contract impact: none
1 parent 1a0257a commit 8330a06

File tree

1 file changed

+42
-5
lines changed

1 file changed

+42
-5
lines changed

server.mjs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,19 @@ process.on("uncaughtException", (err) => {
5858
const app = express();
5959
app.use(express.json({ limit: "2mb" }));
6060

61+
// Force JSON errors (prevents Express HTML error pages)
62+
app.use((err, req, res, next) => {
63+
if (err) {
64+
return res.status(400).json({
65+
ok: false,
66+
error: "invalid_json",
67+
message: err.message,
68+
...instancePayload(),
69+
});
70+
}
71+
next();
72+
});
73+
6174
// basic CORS (no deps)
6275
app.use((req, res, next) => {
6376
res.setHeader("Access-Control-Allow-Origin", "*");
@@ -214,9 +227,15 @@ function normalizePemLoose(input) {
214227

215228
function decodeB64Strict(s) {
216229
try {
217-
const cleaned = String(s || "").replace(/\s+/g, "");
230+
const cleaned0 = String(s || "").replace(/\s+/g, "");
231+
if (!cleaned0) return null;
232+
233+
let cleaned = cleaned0.replace(/-/g, "+").replace(/_/g, "/");
234+
const pad = cleaned.length % 4;
235+
if (pad) cleaned += "=".repeat(4 - pad);
236+
218237
const out = Buffer.from(cleaned, "base64");
219-
if (out.length === 0 && cleaned.length) return null;
238+
if (!out.length) return null;
220239
return out;
221240
} catch {
222241
return null;
@@ -563,10 +582,10 @@ async function withTimeout(promise, ms, label = "timeout") {
563582
function parseEd25519Txt(txt) {
564583
if (!txt) return null;
565584
const s = String(txt).trim();
566-
const m = s.match(/^ed25519:([A-Za-z0-9+/=]+)$/i);
585+
const m = s.match(/^ed25519:([A-Za-z0-9+/_=-]+)$/i);
567586
if (!m) return null;
568-
const raw = Buffer.from(m[1], "base64");
569-
if (raw.length !== 32) return null;
587+
const raw = decodeB64Strict(m[1]);
588+
if (!raw || raw.length !== 32) return null;
570589
return raw;
571590
}
572591

@@ -1813,3 +1832,21 @@ app.post("/verify", async (req, res) => {
18131832
}
18141833
});
18151834
// verb routes
1835+
// -----------------------
1836+
for (const verb of ENABLED_VERBS) {
1837+
app.post(`/${verb}/v${API_VERSION}`, (req, res) => handleVerb(verb, req, res));
1838+
}
1839+
1840+
// JSON 404 for any unknown routes
1841+
app.use((req, res) => {
1842+
res.status(404).json({ ok: false, error: "not_found", path: req.path, ...instancePayload() });
1843+
});
1844+
1845+
// -----------------------
1846+
// boot + listen
1847+
// -----------------------
1848+
initializeSignerConfigOrThrow();
1849+
1850+
app.listen(PORT, HOST, () => {
1851+
console.log(`runtime listening on http://${HOST}:${PORT}`);
1852+
});

0 commit comments

Comments
 (0)