* Builds the `x-zenstack-signature` header value for a request. * The payload is: * - GET / DELETE: the raw query string (URL-encoded, after `?`) * - other methods: `JSON.stringify(body)` (the raw request body)
(options: {
privateKey: string;
method: string;
/** Path + optional query string, e.g. `/api/model/user/findMany?q=%7B%7D` */
pathWithQuery: string;
body?: unknown;
authorizationToken?: string;
/** Override timestamp (unix seconds as string). Defaults to `now`. */
timestamp?: string;
})
| 26 | * - other methods: `JSON.stringify(body)` (the raw request body) |
| 27 | */ |
| 28 | function buildSignatureHeader(options: { |
| 29 | privateKey: string; |
| 30 | method: string; |
| 31 | /** Path + optional query string, e.g. `/api/model/user/findMany?q=%7B%7D` */ |
| 32 | pathWithQuery: string; |
| 33 | body?: unknown; |
| 34 | authorizationToken?: string; |
| 35 | /** Override timestamp (unix seconds as string). Defaults to `now`. */ |
| 36 | timestamp?: string; |
| 37 | }): string { |
| 38 | const timestamp = options.timestamp ?? String(Math.floor(Date.now() / 1000)); |
| 39 | |
| 40 | const method = options.method.toUpperCase(); |
| 41 | let payload: string; |
| 42 | if (method === 'GET' || method === 'DELETE') { |
| 43 | const qMark = options.pathWithQuery.indexOf('?'); |
| 44 | payload = qMark >= 0 ? options.pathWithQuery.substring(qMark + 1) : ''; |
| 45 | } else { |
| 46 | payload = options.body != null ? JSON.stringify(options.body) : ''; |
| 47 | } |
| 48 | |
| 49 | const message = options.authorizationToken |
| 50 | ? `${payload}${timestamp}${options.authorizationToken}` |
| 51 | : `${payload}${timestamp}`; |
| 52 | |
| 53 | const sig = sign(null, Buffer.from(message, 'utf8'), options.privateKey).toString('base64url'); |
| 54 | return `t=${timestamp},v1=${sig}`; |
| 55 | } |
| 56 | |
| 57 | /** Encodes a UserClaim as a plain base64 bearer token. */ |
| 58 | function makeUserToken(claim: { type: 'superUser' } | { type: 'user'; data: Record<string, unknown> }): string { |
no test coverage detected