Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

66 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { test } from "node:test";
3
4import { amzDate, sha256Hex, sign, uriEncode } from "./sigv4.ts";
5
6const EMPTY = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
7
8// AWS's SigV4 test suite, `get-vanilla`: the plainest request there is.
9test("signs AWS's get-vanilla test vector", async () => {
10 const signed = await sign({
11 method: "GET",
12 url: "https://example.amazonaws.com/",
13 payload_hash: EMPTY,
14 region: "us-east-1",
15 service: "service",
16 credentials: { access_key_id: "AKIDEXAMPLE", secret_access_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" },
17 date: new Date("2015-08-30T12:36:00Z"),
18 });
19 assert.equal(signed.canonical_request, `GET\n/\n\nhost:example.amazonaws.com\nx-amz-date:20150830T123600Z\n\nhost;x-amz-date\n${EMPTY}`);
20 assert.equal(
21 signed.string_to_sign,
22 "AWS4-HMAC-SHA256\n20150830T123600Z\n20150830/us-east-1/service/aws4_request\nbb579772317eb040ac9ed261061d46c1f17a8133879d6129b6e1c25292927e63",
23 );
24 assert.equal(signed.signature, "5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31");
25 assert.equal(
26 signed.headers.authorization,
27 "AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31",
28 );
29});
30
31// The S3 documentation's worked example: GET Object with a Range header.
32test("signs the S3 GET Object example", async () => {
33 const signed = await sign({
34 method: "GET",
35 url: "https://examplebucket.s3.amazonaws.com/test.txt",
36 headers: { range: "bytes=0-9", "x-amz-content-sha256": EMPTY },
37 payload_hash: EMPTY,
38 region: "us-east-1",
39 service: "s3",
40 credentials: { access_key_id: "AKIAIOSFODNN7EXAMPLE", secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" },
41 date: new Date("2013-05-24T00:00:00Z"),
42 });
43 assert.equal(signed.signature, "f0e8bdb87c964420e857bd35b5d6ed310bd44f0170aba48dd91039c6036bdb41");
44 assert.match(signed.headers.authorization!, /SignedHeaders=host;range;x-amz-content-sha256;x-amz-date,/);
45});
46
47test("hashes and encodes as SigV4 wants", async () => {
48 assert.equal(await sha256Hex(""), EMPTY);
49 assert.equal(uriEncode("a b/c*~"), "a%20b%2Fc%2A~");
50 assert.equal(amzDate(new Date("2015-08-30T12:36:00.123Z")), "20150830T123600Z");
51});
52
53test("puts the query in order", async () => {
54 const signed = await sign({
55 method: "GET",
56 url: "https://example.amazonaws.com/?Param2=value2&Param1=value1",
57 payload_hash: EMPTY,
58 region: "us-east-1",
59 service: "service",
60 credentials: { access_key_id: "AKIDEXAMPLE", secret_access_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" },
61 date: new Date("2015-08-30T12:36:00Z"),
62 });
63 assert.equal(signed.canonical_request.split("\n")[2], "Param1=value1&Param2=value2");
64 // AWS's `get-vanilla-query-order-key-case`.
65 assert.equal(signed.signature, "b97d918cfa904a5beff61c982a1b6f458b799221646efd99d3219ec94cdf2500");
66});