Skip to content

Commit b7fa2cb

Browse files
committed
feat: generate signature
1 parent 9c53505 commit b7fa2cb

File tree

5 files changed

+81
-1
lines changed

5 files changed

+81
-1
lines changed

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"scripts": {
1313
"lint": "eslint ./src/* && prettier ./ --check",
1414
"pretty": "prettier ./ --write",
15-
"type-check": "tsc --noEmit src/**/*",
15+
"type-check": "tsc --noEmit",
1616
"build": "tsup",
1717
"test": "jest"
1818
},
@@ -25,6 +25,7 @@
2525
"@eslint/js": "^9.11.1",
2626
"@types/eslint__js": "^8.42.3",
2727
"@types/jest": "^29.5.13",
28+
"@types/jsonwebtoken": "^9.0.7",
2829
"eslint": "^9.11.1",
2930
"eslint-config-prettier": "^9.1.0",
3031
"eslint-plugin-jest": "^28.8.3",

src/lib/Client.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { TEST_KEY } from "../__test__/TEST_KEY"
22
import { DatarockClient } from "./Client"
3+
34
describe("DatarockClient", () => {
45
const email = "[email protected]"
56
const privateKey = TEST_KEY

src/lib/utils.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { generateRequestHeaders } from "./utils"
2+
import { TEST_KEY } from "../__test__/TEST_KEY"
3+
4+
describe("generateRequestHeaders()", () => {
5+
const email = "[email protected]"
6+
const requestUrl = "https://someurl.com"
7+
8+
it("generates request headers", () => {
9+
const headers = generateRequestHeaders({
10+
email,
11+
privateKey: TEST_KEY,
12+
requestUrl,
13+
})
14+
const expected = {
15+
signature: expect.any(String),
16+
"x-api-user": email,
17+
}
18+
expect(headers).toEqual(expected)
19+
})
20+
21+
test.each`
22+
privateKey | requestUrl | email | issuedTime
23+
${undefined} | ${requestUrl} | ${email} | ${new Date()}
24+
${TEST_KEY} | ${undefined} | ${email} | ${new Date()}
25+
${TEST_KEY} | ${requestUrl} | ${undefined} | ${new Date()}
26+
`("throws an error if headers are missing", (headers) => {
27+
expect(() => {
28+
generateRequestHeaders(headers)
29+
}).toThrow("is required when generating request headers!")
30+
})
31+
})

src/lib/utils.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { createHash } from "crypto"
2+
import jwt from "jsonwebtoken"
3+
4+
const REQUIRED_PARAMS = ["privateKey", "requestUrl", "email", "issuedTime"]
5+
interface RequestParams {
6+
privateKey: string
7+
requestUrl: string
8+
email: string
9+
issuedTime?: Date
10+
}
11+
function validatRequestParams(params: RequestParams): void {
12+
REQUIRED_PARAMS.forEach((key) => {
13+
// @ts-expect-error the keys match RequestParams
14+
if (!params[key] || params[key] === "") {
15+
throw new Error(`${key} is required when generating request headers!`)
16+
}
17+
})
18+
}
19+
export function generateRequestHeaders({
20+
privateKey,
21+
requestUrl,
22+
email,
23+
issuedTime = new Date(),
24+
}: RequestParams) {
25+
validatRequestParams({ privateKey, requestUrl, email, issuedTime })
26+
const iat = Math.floor(issuedTime.getTime() / 1000)
27+
const requestStringToHash = `${email}/${iat}/${requestUrl}`
28+
const jwtPayload = {
29+
requestHash: createHash("sha512").update(requestStringToHash).digest("hex"),
30+
iat,
31+
}
32+
33+
return {
34+
signature: jwt.sign(jwtPayload, privateKey, { algorithm: "RS256" }),
35+
"x-api-user": email,
36+
}
37+
}

0 commit comments

Comments
 (0)