@@ -58,6 +58,19 @@ process.on("uncaughtException", (err) => {
5858const app = express ( ) ;
5959app . 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)
6275app . use ( ( req , res , next ) => {
6376 res . setHeader ( "Access-Control-Allow-Origin" , "*" ) ;
@@ -214,9 +227,15 @@ function normalizePemLoose(input) {
214227
215228function 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") {
563582function parseEd25519Txt ( txt ) {
564583 if ( ! txt ) return null ;
565584 const s = String ( txt ) . trim ( ) ;
566- const m = s . match ( / ^ e d 2 5 5 1 9 : ( [ A - Z a - z 0 - 9 + / = ] + ) $ / i) ;
585+ const m = s . match ( / ^ e d 2 5 5 1 9 : ( [ A - Z a - z 0 - 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