@aws-sdk/cloudfront-signer 3.90.0

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.
@@ -0,0 +1,577 @@
1
+ import { parseUrl } from "@aws-sdk/url-parser";
2
+ import { createSign, createVerify } from "crypto";
3
+ import { mkdtempSync, rmdirSync, writeFileSync } from "fs";
4
+ import { tmpdir } from "os";
5
+ import { resolve } from "path";
6
+
7
+ import { getSignedCookies, getSignedUrl } from "./index";
8
+
9
+ const url = "https://d111111abcdef8.cloudfront.net/private-content/private.jpeg";
10
+ const keyPairId = "APKAEIBAERJR2EXAMPLE";
11
+ const dateLessThan = "2020-01-01";
12
+ const epochDateLessThan = Math.round(new Date(dateLessThan).getTime() / 1000);
13
+ const dateGreaterThan = "2019-12-01";
14
+ const epochDateGreaterThan = Math.round(new Date(dateGreaterThan).getTime() / 1000);
15
+ const ipAddress = "10.0.0.0";
16
+ const privateKey = Buffer.from(`
17
+ -----BEGIN RSA PRIVATE KEY-----
18
+ MIIEowIBAAKCAQEAuHfxvylv0IgfsJkualzZtCqwLyg19Gcsy+jVAAioVtWBOgxE
19
+ IYSsED+yzryecDnniJGokXiGTt6nlJk5o95jNSnKw9KOThWey95WudDnEcUWKJow
20
+ dlcA1B2iXBx4cmwwdekNxs/hHZjubY+kHuaDc0D/tJYyiN7t84wQA/slRHZ0tDBy
21
+ pGI4LeNFn3fmu4dvHcvSYFoa1sV/FDe0P6OHjrkG36XE6gh9+yHEFLAsGzuWZlIH
22
+ KmdPx8wuz/73GPnQ/P3+sGjwVjimtzEo5R6VoyMHWHRjenjxN/oFrtizXXuRDsKw
23
+ 9Vvg8FO3MUsYAEWmKZM3DI9/+niZl/GCjgCIlQIDAQABAoIBAQCX1mKuLrVSuDkd
24
+ a3jBI9wuaFTM/BQtMB+3V9a7SGUH1IWh+ia6UDIwzb2oXaksRv1FdF+EHeivUqYt
25
+ slG3iH2wbM3xkYaAz1r+A+zu1fzcq5UppoDtZ3/PGPVjTCv4QwVAiKxGUSXC7vaS
26
+ SAGXTbY1T/Mp+dduwdCq/0bPgBGU32WzAGtx/JCnKD8brShrcwuGtirDq4c9Pq0T
27
+ FOApejyMoYwN0Z6jkErU1qSiEKp/SZrQTO+5BoyjwlZTe8dWjAw4srJ4jH9q1zxm
28
+ OZDT+80HnV6FiWqlitqDWQJvPhpW/PMTEmklZZw1WThqRxtm2Xee/KAD5grq+Xho
29
+ 5xp30A4BAoGBAOXFrkOW65Z8GYzyCjw7XgFkSLA4Dhiwzebxdkv+s2NzHhzGz7pf
30
+ Dqe8pQ/bS1B6PLi9v+f8RjP9f1bY3QPxYwfYLwhL/JB4pvLNcGRUQ0fSzWcpmhWH
31
+ FN0V6K0kDswC9QL3vbEg9V/MM6EvwNxCPiZB6NQtOqhd48ErZ2cRQKBFAoGBAM2G
32
+ aqcWYpyDd06Vc7iVN1QqabpGkDfdk8XC/21ZTOZOQocplv9k+kzSxce8KMZxyQVm
33
+ K7D6Atx9uqEdqEutvgdYrJa+Br3VL2oLcBiYPOhuJROyl7Zl8bBeanYAhDraZWbL
34
+ tVP/6h9dzowPvcNm6e6SVl+uShqKJb4tv0fftpQRAoGAEXhpWpxEB2oiKzRQEOpW
35
+ qHZujG+Gqtvum+uqGfcgvqQHGxsGul316E0Qo9cBr/nLWiSbTdFBqTxSDVFp5J3a
36
+ 8MLAOLpGVtnFn9p8/DPn9bMSiRCBtbdSn8jFqzx9n4duB668jpY58fG9zzipSlYD
37
+ EbebM17JAfo5kftx3kVSi50CgYBPXPd0PA2qOI3ql4WPIneyFYqsNrFcEUEN3cW6
38
+ mQA78r536RR43KpW3hEnlr38G1YvsotulKxkLlzR+FzTlGzL82756rk5tsfPYElS
39
+ Bf+HFXlVyOISuf0BSQQ9OufUvh7n+gO0Qx9KK3Ql27JAcU4mJPYbjnbpFq2Kaany
40
+ fC3JsQKBgANzZbf9D0lgQE1wsb45fzrAPAqRQHeVY7V8sZPQoJFcZ2Ymp/3L/UHc
41
+ NwfPmGXHQDQaK9I3XpHfbyOelD6ghHi/wZj0sKR3Uoo84n8sIpCdUvwitjlHlZBE
42
+ aoCHJ9c5Pnu6FwMAjP8aaKLQDvoHZKVWL2Ml6A6V3Ed95Itp/g2J
43
+ -----END RSA PRIVATE KEY-----`);
44
+
45
+ function createSignature(data: string): string {
46
+ const signer = createSign("RSA-SHA1");
47
+ signer.update(data);
48
+ return normalizeBase64(signer.sign(privateKey, "base64"));
49
+ }
50
+ function verifySignature(signature: string, data: string): boolean {
51
+ const verifier = createVerify("RSA-SHA1");
52
+ verifier.update(data);
53
+ return verifier.verify(privateKey, signature, "base64");
54
+ }
55
+ function encodeToBase64(str: string): string {
56
+ return normalizeBase64(Buffer.from(str).toString("base64"));
57
+ }
58
+ function normalizeBase64(str: string): string {
59
+ return str.replace(/\+/g, "-").replace(/=/g, "_").replace(/\//g, "~");
60
+ }
61
+ function denormalizeBase64(str: string): string {
62
+ return str.replace(/\-/g, "+").replace(/_/g, "=").replace(/~/g, "/");
63
+ }
64
+
65
+ describe("getSignedUrl", () => {
66
+ it("should maintain query params after signing a URL", () => {
67
+ const url = "https://example.com/private.jpeg?foo=bar";
68
+ const result = parseUrl(
69
+ getSignedUrl({
70
+ url,
71
+ keyPairId,
72
+ dateLessThan,
73
+ privateKey,
74
+ })
75
+ );
76
+ if (!result.query) {
77
+ throw new Error("query parameter is undefined");
78
+ }
79
+ expect(result.query["foo"]).toBe("bar");
80
+ });
81
+ it("should include url path in policy of signed URL", () => {
82
+ const url = "https://example.com/private.jpeg?foo=bar";
83
+ const result = parseUrl(
84
+ getSignedUrl({
85
+ url,
86
+ keyPairId,
87
+ dateLessThan,
88
+ privateKey,
89
+ })
90
+ );
91
+ if (!result.query) {
92
+ throw new Error("query parameter is undefined");
93
+ }
94
+ expect(result.query["Signature"]).toBeDefined();
95
+ const signatureQueryParam = denormalizeBase64(result.query["Signature"] as string);
96
+ const policyStr = JSON.stringify({
97
+ Statement: [
98
+ {
99
+ Resource: url,
100
+ Condition: {
101
+ DateLessThan: {
102
+ "AWS:EpochTime": epochDateLessThan,
103
+ },
104
+ },
105
+ },
106
+ ],
107
+ });
108
+ expect(verifySignature(signatureQueryParam, policyStr)).toBeTruthy();
109
+ });
110
+ it("should sign a URL with a canned policy", () => {
111
+ const result = getSignedUrl({
112
+ url,
113
+ keyPairId,
114
+ dateLessThan,
115
+ privateKey,
116
+ });
117
+ const policyStr = JSON.stringify({
118
+ Statement: [
119
+ {
120
+ Resource: url,
121
+ Condition: {
122
+ DateLessThan: {
123
+ "AWS:EpochTime": epochDateLessThan,
124
+ },
125
+ },
126
+ },
127
+ ],
128
+ });
129
+ const signature = createSignature(policyStr);
130
+ expect(result).toBe(`${url}?Expires=${epochDateLessThan}&Key-Pair-Id=${keyPairId}&Signature=${signature}`);
131
+ const parsedUrl = parseUrl(result);
132
+ expect(parsedUrl).toBeDefined();
133
+ const signatureQueryParam = denormalizeBase64(parsedUrl.query["Signature"] as string);
134
+ expect(verifySignature(signatureQueryParam, policyStr)).toBeTruthy();
135
+ });
136
+ it("should sign a URL with a custom policy containing a start date", () => {
137
+ const result = getSignedUrl({
138
+ url,
139
+ keyPairId,
140
+ dateLessThan,
141
+ dateGreaterThan,
142
+ privateKey,
143
+ });
144
+ const policyStr = JSON.stringify({
145
+ Statement: [
146
+ {
147
+ Resource: url,
148
+ Condition: {
149
+ DateLessThan: {
150
+ "AWS:EpochTime": epochDateLessThan,
151
+ },
152
+ DateGreaterThan: {
153
+ "AWS:EpochTime": epochDateGreaterThan,
154
+ },
155
+ },
156
+ },
157
+ ],
158
+ });
159
+ const signature = createSignature(policyStr);
160
+ expect(result).toBe(`${url}?Policy=${encodeToBase64(policyStr)}&Key-Pair-Id=${keyPairId}&Signature=${signature}`);
161
+ const parsedUrl = parseUrl(result);
162
+ expect(parsedUrl).toBeDefined();
163
+ const signatureQueryParam = denormalizeBase64(parsedUrl.query["Signature"] as string);
164
+ expect(verifySignature(signatureQueryParam, policyStr)).toBeTruthy();
165
+ });
166
+ it("should sign a URL with a custom policy containing an ip address", () => {
167
+ const result = getSignedUrl({
168
+ url,
169
+ keyPairId,
170
+ dateLessThan,
171
+ ipAddress,
172
+ privateKey,
173
+ });
174
+ const policyStr = JSON.stringify({
175
+ Statement: [
176
+ {
177
+ Resource: url,
178
+ Condition: {
179
+ DateLessThan: {
180
+ "AWS:EpochTime": epochDateLessThan,
181
+ },
182
+ IpAddress: {
183
+ "AWS:SourceIp": `${ipAddress}/32`,
184
+ },
185
+ },
186
+ },
187
+ ],
188
+ });
189
+ const signature = createSignature(policyStr);
190
+ expect(result).toBe(`${url}?Policy=${encodeToBase64(policyStr)}&Key-Pair-Id=${keyPairId}&Signature=${signature}`);
191
+ const parsedUrl = parseUrl(result);
192
+ expect(parsedUrl).toBeDefined();
193
+ const signatureQueryParam = denormalizeBase64(parsedUrl.query["Signature"] as string);
194
+ expect(verifySignature(signatureQueryParam, policyStr)).toBeTruthy();
195
+ });
196
+ it("should sign a URL with a custom policy containing a start date and ip address", () => {
197
+ const result = getSignedUrl({
198
+ url,
199
+ keyPairId,
200
+ dateLessThan,
201
+ dateGreaterThan,
202
+ ipAddress,
203
+ privateKey,
204
+ });
205
+ const policyStr = JSON.stringify({
206
+ Statement: [
207
+ {
208
+ Resource: url,
209
+ Condition: {
210
+ DateLessThan: {
211
+ "AWS:EpochTime": epochDateLessThan,
212
+ },
213
+ DateGreaterThan: {
214
+ "AWS:EpochTime": epochDateGreaterThan,
215
+ },
216
+ IpAddress: {
217
+ "AWS:SourceIp": `${ipAddress}/32`,
218
+ },
219
+ },
220
+ },
221
+ ],
222
+ });
223
+ const signature = createSignature(policyStr);
224
+ expect(result).toBe(`${url}?Policy=${encodeToBase64(policyStr)}&Key-Pair-Id=${keyPairId}&Signature=${signature}`);
225
+ const parsedUrl = parseUrl(result);
226
+ expect(parsedUrl).toBeDefined();
227
+ const signatureQueryParam = denormalizeBase64(parsedUrl.query["Signature"] as string);
228
+ expect(verifySignature(signatureQueryParam, policyStr)).toBeTruthy();
229
+ });
230
+ it("should allow an ip address with and without a mask", () => {
231
+ const baseArgs = {
232
+ url,
233
+ keyPairId,
234
+ dateLessThan,
235
+ privateKey,
236
+ };
237
+ expect(
238
+ getSignedUrl({
239
+ ...baseArgs,
240
+ ipAddress: "10.0.0.0/32",
241
+ })
242
+ ).toBeTruthy();
243
+ expect(
244
+ getSignedUrl({
245
+ ...baseArgs,
246
+ ipAddress: "10.0.0.0",
247
+ })
248
+ ).toBeTruthy();
249
+ });
250
+ it("should throw an error when the ip address is invalid", () => {
251
+ const baseArgs = {
252
+ url,
253
+ keyPairId,
254
+ dateLessThan,
255
+ privateKey,
256
+ };
257
+ expect(() =>
258
+ getSignedUrl({
259
+ ...baseArgs,
260
+ ipAddress: "10.0.0.0/",
261
+ })
262
+ ).toThrow('IP address "10.0.0.0/" is invalid due to missing ip or mask part of CIDR.');
263
+ expect(() =>
264
+ getSignedUrl({
265
+ ...baseArgs,
266
+ ipAddress: "/32",
267
+ })
268
+ ).toThrow('IP address "/32" is invalid due to missing ip or mask part of CIDR.');
269
+ expect(() =>
270
+ getSignedUrl({
271
+ ...baseArgs,
272
+ ipAddress: "10.0.0.0/-1",
273
+ })
274
+ ).toThrow('IP address "10.0.0.0/-1" is invalid due to invalid mask.');
275
+ expect(() =>
276
+ getSignedUrl({
277
+ ...baseArgs,
278
+ ipAddress: "10.0.0.0/33",
279
+ })
280
+ ).toThrow('IP address "10.0.0.0/33" is invalid due to invalid mask.');
281
+ expect(() =>
282
+ getSignedUrl({
283
+ ...baseArgs,
284
+ ipAddress: "10.0.0.-1",
285
+ })
286
+ ).toThrow('IP address "10.0.0.-1" is invalid due to invalid IP octets.');
287
+ expect(() =>
288
+ getSignedUrl({
289
+ ...baseArgs,
290
+ ipAddress: "10.0.0.256",
291
+ })
292
+ ).toThrow('IP address "10.0.0.256" is invalid due to invalid IP octets.');
293
+ });
294
+ it("should sign a RTMP URL", () => {
295
+ const url = "rtmp://d111111abcdef8.cloudfront.net/private-content/private.jpeg";
296
+ const result = getSignedUrl({
297
+ url,
298
+ keyPairId,
299
+ dateLessThan,
300
+ privateKey,
301
+ });
302
+ const policyStr = JSON.stringify({
303
+ Statement: [
304
+ {
305
+ Resource: "private-content/private.jpeg",
306
+ Condition: {
307
+ DateLessThan: {
308
+ "AWS:EpochTime": epochDateLessThan,
309
+ },
310
+ },
311
+ },
312
+ ],
313
+ });
314
+ const signature = createSignature(policyStr);
315
+ expect(result).toBe(
316
+ `private-content/private.jpeg?Expires=${epochDateLessThan}&Key-Pair-Id=${keyPairId}&Signature=${signature}`
317
+ );
318
+ expect(verifySignature(denormalizeBase64(signature), policyStr)).toBeTruthy();
319
+ });
320
+ it("should sign a URL with a policy provided by the user", () => {
321
+ const policy = '{"foo":"bar"}';
322
+ const result = getSignedUrl({
323
+ url,
324
+ keyPairId,
325
+ privateKey,
326
+ policy,
327
+ });
328
+ const signature = createSignature(policy);
329
+ expect(result).toBe(`${url}?Policy=${encodeToBase64(policy)}&Key-Pair-Id=${keyPairId}&Signature=${signature}`);
330
+ const signatureQueryParam = denormalizeBase64(signature);
331
+ expect(verifySignature(signatureQueryParam, policy)).toBeTruthy();
332
+ });
333
+ });
334
+
335
+ describe("getSignedCookies", () => {
336
+ it("should allow an ip address with and without a mask", () => {
337
+ const baseArgs = {
338
+ url,
339
+ keyPairId,
340
+ dateLessThan,
341
+ privateKey,
342
+ };
343
+ expect(
344
+ getSignedCookies({
345
+ ...baseArgs,
346
+ ipAddress: "10.0.0.0/32",
347
+ })
348
+ ).toBeTruthy();
349
+ expect(
350
+ getSignedCookies({
351
+ ...baseArgs,
352
+ ipAddress: "10.0.0.0",
353
+ })
354
+ ).toBeTruthy();
355
+ });
356
+ it("should throw an error when the ip address is invalid", () => {
357
+ const baseArgs = {
358
+ url,
359
+ keyPairId,
360
+ dateLessThan,
361
+ privateKey,
362
+ };
363
+ expect(() =>
364
+ getSignedCookies({
365
+ ...baseArgs,
366
+ ipAddress: "10.0.0.0/",
367
+ })
368
+ ).toThrow('IP address "10.0.0.0/" is invalid due to missing ip or mask part of CIDR.');
369
+ expect(() =>
370
+ getSignedCookies({
371
+ ...baseArgs,
372
+ ipAddress: "/32",
373
+ })
374
+ ).toThrow('IP address "/32" is invalid due to missing ip or mask part of CIDR.');
375
+ expect(() =>
376
+ getSignedCookies({
377
+ ...baseArgs,
378
+ ipAddress: "10.0.0.0/-1",
379
+ })
380
+ ).toThrow('IP address "10.0.0.0/-1" is invalid due to invalid mask.');
381
+ expect(() =>
382
+ getSignedCookies({
383
+ ...baseArgs,
384
+ ipAddress: "10.0.0.0/33",
385
+ })
386
+ ).toThrow('IP address "10.0.0.0/33" is invalid due to invalid mask.');
387
+ expect(() =>
388
+ getSignedCookies({
389
+ ...baseArgs,
390
+ ipAddress: "10.0.0.-1",
391
+ })
392
+ ).toThrow('IP address "10.0.0.-1" is invalid due to invalid IP octets.');
393
+ expect(() =>
394
+ getSignedCookies({
395
+ ...baseArgs,
396
+ ipAddress: "10.0.0.256",
397
+ })
398
+ ).toThrow('IP address "10.0.0.256" is invalid due to invalid IP octets.');
399
+ });
400
+ it("should be able sign cookies that contain a URL with wildcards", () => {
401
+ const url = "https://example.com/private-content/*";
402
+ const result = getSignedCookies({
403
+ url,
404
+ keyPairId,
405
+ dateLessThan,
406
+ privateKey,
407
+ });
408
+ const policyStr = JSON.stringify({
409
+ Statement: [
410
+ {
411
+ Resource: url,
412
+ Condition: {
413
+ DateLessThan: {
414
+ "AWS:EpochTime": epochDateLessThan,
415
+ },
416
+ },
417
+ },
418
+ ],
419
+ });
420
+ expect(verifySignature(denormalizeBase64(result["CloudFront-Signature"]), policyStr)).toBeTruthy();
421
+ });
422
+ it("should sign cookies with a canned policy", () => {
423
+ const result = getSignedCookies({
424
+ url,
425
+ keyPairId,
426
+ dateLessThan,
427
+ privateKey,
428
+ });
429
+ const policyStr = JSON.stringify({
430
+ Statement: [
431
+ {
432
+ Resource: url,
433
+ Condition: {
434
+ DateLessThan: {
435
+ "AWS:EpochTime": epochDateLessThan,
436
+ },
437
+ },
438
+ },
439
+ ],
440
+ });
441
+ const signature = createSignature(policyStr);
442
+ const expected = {
443
+ "CloudFront-Expires": epochDateLessThan,
444
+ "CloudFront-Key-Pair-Id": keyPairId,
445
+ "CloudFront-Signature": signature,
446
+ };
447
+ expect(result["CloudFront-Expires"]).toBe(expected["CloudFront-Expires"]);
448
+ expect(result["CloudFront-Key-Pair-Id"]).toBe(expected["CloudFront-Key-Pair-Id"]);
449
+ expect(result["CloudFront-Signature"]).toBe(expected["CloudFront-Signature"]);
450
+ expect(verifySignature(denormalizeBase64(result["CloudFront-Signature"]), policyStr)).toBeTruthy();
451
+ });
452
+ it("should sign cookies with a custom policy containing a start date", () => {
453
+ const result = getSignedCookies({
454
+ url,
455
+ keyPairId,
456
+ dateLessThan,
457
+ dateGreaterThan,
458
+ privateKey,
459
+ });
460
+ const policyStr = JSON.stringify({
461
+ Statement: [
462
+ {
463
+ Resource: url,
464
+ Condition: {
465
+ DateLessThan: {
466
+ "AWS:EpochTime": epochDateLessThan,
467
+ },
468
+ DateGreaterThan: {
469
+ "AWS:EpochTime": epochDateGreaterThan,
470
+ },
471
+ },
472
+ },
473
+ ],
474
+ });
475
+ const signature = createSignature(policyStr);
476
+ const expected = {
477
+ "CloudFront-Policy": encodeToBase64(policyStr),
478
+ "CloudFront-Key-Pair-Id": keyPairId,
479
+ "CloudFront-Signature": signature,
480
+ };
481
+ expect(result["CloudFront-Policy"]).toBe(expected["CloudFront-Policy"]);
482
+ expect(result["CloudFront-Key-Pair-Id"]).toBe(expected["CloudFront-Key-Pair-Id"]);
483
+ expect(result["CloudFront-Signature"]).toBe(expected["CloudFront-Signature"]);
484
+ expect(verifySignature(denormalizeBase64(result["CloudFront-Signature"]), policyStr)).toBeTruthy();
485
+ });
486
+ it("should sign cookies with a custom policy containing an ip address", () => {
487
+ const result = getSignedCookies({
488
+ url,
489
+ keyPairId,
490
+ dateLessThan,
491
+ ipAddress,
492
+ privateKey,
493
+ });
494
+ const policyStr = JSON.stringify({
495
+ Statement: [
496
+ {
497
+ Resource: url,
498
+ Condition: {
499
+ DateLessThan: {
500
+ "AWS:EpochTime": epochDateLessThan,
501
+ },
502
+ IpAddress: {
503
+ "AWS:SourceIp": `${ipAddress}/32`,
504
+ },
505
+ },
506
+ },
507
+ ],
508
+ });
509
+ const signature = createSignature(policyStr);
510
+ const expected = {
511
+ "CloudFront-Policy": encodeToBase64(policyStr),
512
+ "CloudFront-Key-Pair-Id": keyPairId,
513
+ "CloudFront-Signature": signature,
514
+ };
515
+ expect(result["CloudFront-Policy"]).toBe(expected["CloudFront-Policy"]);
516
+ expect(result["CloudFront-Key-Pair-Id"]).toBe(expected["CloudFront-Key-Pair-Id"]);
517
+ expect(result["CloudFront-Signature"]).toBe(expected["CloudFront-Signature"]);
518
+ expect(verifySignature(denormalizeBase64(result["CloudFront-Signature"]), policyStr)).toBeTruthy();
519
+ });
520
+ it("should sign cookies with a custom policy containing a start date and ip address", () => {
521
+ const result = getSignedCookies({
522
+ url,
523
+ keyPairId,
524
+ dateLessThan,
525
+ dateGreaterThan,
526
+ ipAddress,
527
+ privateKey,
528
+ });
529
+ const policyStr = JSON.stringify({
530
+ Statement: [
531
+ {
532
+ Resource: url,
533
+ Condition: {
534
+ DateLessThan: {
535
+ "AWS:EpochTime": epochDateLessThan,
536
+ },
537
+ DateGreaterThan: {
538
+ "AWS:EpochTime": epochDateGreaterThan,
539
+ },
540
+ IpAddress: {
541
+ "AWS:SourceIp": `${ipAddress}/32`,
542
+ },
543
+ },
544
+ },
545
+ ],
546
+ });
547
+ const signature = createSignature(policyStr);
548
+ const expected = {
549
+ "CloudFront-Policy": encodeToBase64(policyStr),
550
+ "CloudFront-Key-Pair-Id": keyPairId,
551
+ "CloudFront-Signature": signature,
552
+ };
553
+ expect(result["CloudFront-Policy"]).toBe(expected["CloudFront-Policy"]);
554
+ expect(result["CloudFront-Key-Pair-Id"]).toBe(expected["CloudFront-Key-Pair-Id"]);
555
+ expect(result["CloudFront-Signature"]).toBe(expected["CloudFront-Signature"]);
556
+ expect(verifySignature(denormalizeBase64(result["CloudFront-Signature"]), policyStr)).toBeTruthy();
557
+ });
558
+ it("should sign a URL with a policy provided by the user", () => {
559
+ const policy = '{"foo":"bar"}';
560
+ const result = getSignedCookies({
561
+ url,
562
+ keyPairId,
563
+ privateKey,
564
+ policy,
565
+ });
566
+ const signature = createSignature(policy);
567
+ const expected = {
568
+ "CloudFront-Policy": encodeToBase64(policy),
569
+ "CloudFront-Key-Pair-Id": keyPairId,
570
+ "CloudFront-Signature": signature,
571
+ };
572
+ expect(result["CloudFront-Policy"]).toBe(expected["CloudFront-Policy"]);
573
+ expect(result["CloudFront-Key-Pair-Id"]).toBe(expected["CloudFront-Key-Pair-Id"]);
574
+ expect(result["CloudFront-Signature"]).toBe(expected["CloudFront-Signature"]);
575
+ expect(verifySignature(denormalizeBase64(result["CloudFront-Signature"]), policy)).toBeTruthy();
576
+ });
577
+ });