@stacksjs/router 0.74.32 → 0.74.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/signed-url.js +1 -1
- package/package.json +18 -18
package/dist/signed-url.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{Buffer}from"node:buffer";import process from"node:process";import{url as buildUrl}from"./stacks-router";const SIGNATURE_PARAM="signature",EXPIRES_PARAM="expires";function getSigningSecret(){const secret=process.env.APP_KEY||process.env.STACKS_SIGNED_URL_SECRET;if(!secret||secret.length<16)throw Error("[router] signed URLs require APP_KEY (\u2265 16 chars) or STACKS_SIGNED_URL_SECRET. "+"Run `./buddy key:generate` or set the env var.");return secret}function hmacHex(payload,secret){return new Bun.CryptoHasher("sha256",secret).update(payload).digest("hex")}let nativeTimingSafeEqual;function timingSafeEqual(a,b){nativeTimingSafeEqual??=process.getBuiltinModule("node:crypto").timingSafeEqual;return nativeTimingSafeEqual(a,b)}function safeEqualHex(a,b){const ba=Buffer.from(a.toLowerCase(),"hex"),bb=Buffer.from(b.toLowerCase(),"hex");if(ba.length!==bb.length)return!1;return timingSafeEqual(ba,bb)}function stripSignatureParam(input){const u=new URL(input.toString());u.searchParams.delete(SIGNATURE_PARAM);return u}function buildSignaturePayload(input){const stripped=stripSignatureParam(input);stripped.searchParams.sort();return stripped.toString()}export function signUrl(input,options={}){const secret=getSigningSecret(),url=input.startsWith("http")?new URL(input):new URL(input.startsWith("/")?input:`/${input}`,process.env.APP_URL||"https://localhost");if(options.ttl!==void 0&&options.expiresAt!==void 0)warnOnce("dual-expiry","[router] signUrl: both `ttl` and `expiresAt` provided - using `ttl`.");if(options.ttl!==void 0)url.searchParams.set(EXPIRES_PARAM,String(Math.floor(Date.now()/1000)+options.ttl));else if(options.expiresAt!==void 0)url.searchParams.set(EXPIRES_PARAM,String(Math.floor(options.expiresAt)));const payload=buildSignaturePayload(url);url.searchParams.set(SIGNATURE_PARAM,hmacHex(payload,secret));return url.toString()}let _warnedKeys;function warnOnce(key,message){if(_warnedKeys?.has(key))return;(_warnedKeys??=new Set).add(key);console.warn(message)}export function signedUrl(routeName,params={},options={}){return signUrl(buildUrl(routeName,params),options)}export function verifySignedUrl(input){const url=typeof input==="string"?new URL(input,process.env.APP_URL||"https://localhost"):input,presented=url.searchParams.get(SIGNATURE_PARAM);if(!presented)return{valid:!1,reason:"missing-signature"};const expiresRaw=url.searchParams.get(EXPIRES_PARAM);if(expiresRaw!==null){const expires=Number.parseInt(expiresRaw,10);if(!Number.isFinite(expires)||Date.now()/1000>expires)return{valid:!1,reason:"expired"}}try{const expected=hmacHex(buildSignaturePayload(url),getSigningSecret());return safeEqualHex(presented,expected)?{valid:!0}:{valid:!1,reason:"invalid-signature"}}catch{return{valid:!1,reason:"invalid-signature"}}}export async function verifySignedUrlMiddleware(req){const result=verifySignedUrl(req.url);if(result.valid)return;const status=result.reason==="expired"?410:401;throw Response.json({error:result.reason},{status})}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/router",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.74.
|
|
5
|
+
"version": "0.74.33",
|
|
6
6
|
"description": "The Stacks framework router.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -60,28 +60,28 @@
|
|
|
60
60
|
"prepublishOnly": "bun run build"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@stacksjs/bun-router": "^0.1.
|
|
64
|
-
"@stacksjs/cache": "0.74.
|
|
65
|
-
"@stacksjs/collections": "0.74.
|
|
66
|
-
"@stacksjs/config": "0.74.
|
|
67
|
-
"@stacksjs/error-handling": "0.74.
|
|
68
|
-
"@stacksjs/logging": "0.74.
|
|
69
|
-
"@stacksjs/pagination": "0.74.
|
|
70
|
-
"@stacksjs/path": "0.74.
|
|
71
|
-
"@stacksjs/security": "0.74.
|
|
72
|
-
"@stacksjs/storage": "0.74.
|
|
73
|
-
"ts-rate-limiter": "^0.4.
|
|
63
|
+
"@stacksjs/bun-router": "^0.1.15",
|
|
64
|
+
"@stacksjs/cache": "0.74.33",
|
|
65
|
+
"@stacksjs/collections": "0.74.33",
|
|
66
|
+
"@stacksjs/config": "0.74.33",
|
|
67
|
+
"@stacksjs/error-handling": "0.74.33",
|
|
68
|
+
"@stacksjs/logging": "0.74.33",
|
|
69
|
+
"@stacksjs/pagination": "0.74.33",
|
|
70
|
+
"@stacksjs/path": "0.74.33",
|
|
71
|
+
"@stacksjs/security": "0.74.33",
|
|
72
|
+
"@stacksjs/storage": "0.74.33",
|
|
73
|
+
"ts-rate-limiter": "^0.4.10"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@stacksjs/actions": "0.74.
|
|
77
|
-
"@stacksjs/types": "0.74.
|
|
76
|
+
"@stacksjs/actions": "0.74.33",
|
|
77
|
+
"@stacksjs/types": "0.74.33",
|
|
78
78
|
"better-dx": "^0.2.24"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
|
-
"@stacksjs/api": "0.74.
|
|
82
|
-
"@stacksjs/auth": "0.74.
|
|
83
|
-
"@stacksjs/database": "0.74.
|
|
84
|
-
"@stacksjs/validation": "0.74.
|
|
81
|
+
"@stacksjs/api": "0.74.33",
|
|
82
|
+
"@stacksjs/auth": "0.74.33",
|
|
83
|
+
"@stacksjs/database": "0.74.33",
|
|
84
|
+
"@stacksjs/validation": "0.74.33"
|
|
85
85
|
},
|
|
86
86
|
"peerDependenciesMeta": {
|
|
87
87
|
"@stacksjs/api": {
|