Skip to content

Commit 5923ddf

Browse files
authored
feat: introduce v4 signed url (#637)
* feat: v4 signed url WIP * make version an optinoal * lint * add required host header * fix canonical query params joining * add test for defaulting to v2 * fix v4 signing with test * fix tests * refactor post-signing url construction v2/v4 * add v4 tests: response-content-type and generate parameters * convert signature to HEX * add conformance test * npm run fix * remove reduntant toLowerCase * do not promisify getDate() * add system-test for v4 signing * run conformance test along with system test * fix tests * add content-md5 and content-type to signed headers if given * Object.entries in not ES5 * npm run fix * split out conformance test * test: invalid version param given * mock out Date when testing instead of override Date * use Array.map to build canonical query * refactor: use dateformat library instead of writing a function * refactor: remove unused * remove reference to deleted methods * refactor: use string interpolation and dot accessor * refactor: use method chaining * add a comment about singled valued header * refactor signedHeaders * Number(x) * refactor: use query-string module as url.parse is deprecated * npm run fix * use query-string to build canonicalQueryParams * refactor: verb => method * refactor: use sinon.FakeTimers instead of timekeeper * npm run fix * use async/await for new system-test * use async/await for new test (2) * convert getSignedUrl tests to async/await * refactor: correctly filter out undefined header values * npm run fix * make v4 multi-valued header delimiter consistent with v2, (single `,`, no space) * copy stack trace * fix: replace ALL sequential spaces * OutgoingHttpHeaders use generic type .map; rename flattenObject => objectEntries * refactor: use build-in querystring * break up v2/v4 signed url query interface * add comments about the construction of canonical headers * npm run fix * git merge failed to put code in right place * test: assert SigningError thrown * test(v4): resumable upload * prefer string.includes over indexOf * npm run fix * docs: add a note on POST and X-Goog-Resumable * SEVEN_DAYS = 604800 * emit warning when using default version * emitWarning if using default version for signing * restore stub * add new line * test: v4 signed URL: conformance test (#638) * Revert "split out conformance test" This reverts commit ce00255c738e97bf6e3e602f7cca23fae3793d05. * sync conformance-test cases; parse cases without modification * this.skip * refactor: lift interface * remove default v2 warning * docs(samples): Samples for v4 Signed URL (#654) * remove timeout on conformance-test * npm run fix
1 parent ba502fa commit 5923ddf

9 files changed

Lines changed: 800 additions & 160 deletions

File tree

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"type": "service_account",
3+
"project_id": "dummy-project-id",
4+
"private_key_id": "ffffffffffffffffffffffffffffffffffffffff",
5+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCsPzMirIottfQ2\nryjQmPWocSEeGo7f7Q4/tMQXHlXFzo93AGgU2t+clEj9L5loNhLVq+vk+qmnyDz5\nQ04y8jVWyMYzzGNNrGRW/yaYqnqlKZCy1O3bmnNjV7EDbC/jE1ZLBY0U3HaSHfn6\nS9ND8MXdgD0/ulRTWwq6vU8/w6i5tYsU7n2LLlQTl1fQ7/emO9nYcCFJezHZVa0H\nmeWsdHwWsok0skwQYQNIzP3JF9BpR5gJT2gNge6KopDesJeLoLzaX7cUnDn+CAnn\nLuLDwwSsIVKyVxhBFsFXPplgpaQRwmGzwEbf/Xpt9qo26w2UMgn30jsOaKlSeAX8\ncS6ViF+tAgMBAAECggEACKRuJCP8leEOhQziUx8Nmls8wmYqO4WJJLyk5xUMUC22\nSI4CauN1e0V8aQmxnIc0CDkFT7qc9xBmsMoF+yvobbeKrFApvlyzNyM7tEa/exh8\nDGD/IzjbZ8VfWhDcUTwn5QE9DCoon9m1sG+MBNlokB3OVOt8LieAAREdEBG43kJu\nyQTOkY9BGR2AY1FnAl2VZ/jhNDyrme3tp1sW1BJrawzR7Ujo8DzlVcS2geKA9at7\n55ua5GbHz3hfzFgjVXDfnkWzId6aHypUyqHrSn1SqGEbyXTaleKTc6Pgv0PgkJjG\nhZazWWdSuf1T5Xbs0OhAK9qraoAzT6cXXvMEvvPt6QKBgQDXcZKqJAOnGEU4b9+v\nOdoh+nssdrIOBNMu1m8mYbUVYS1aakc1iDGIIWNM3qAwbG+yNEIi2xi80a2RMw2T\n9RyCNB7yqCXXVKLBiwg9FbKMai6Vpk2bWIrzahM9on7AhCax/X2AeOp+UyYhFEy6\nUFG4aHb8THscL7b515ukSuKb5QKBgQDMq+9PuaB0eHsrmL6q4vHNi3MLgijGg/zu\nAXaPygSYAwYW8KglcuLZPvWrL6OG0+CrfmaWTLsyIZO4Uhdj7MLvX6yK7IMnagvk\nL3xjgxSklEHJAwi5wFeJ8ai/1MIuCn8p2re3CbwISKpvf7Sgs/W4196P4vKvTiAz\njcTiSYFIKQKBgCjMpkS4O0TakMlGTmsFnqyOneLmu4NyIHgfPb9cA4n/9DHKLKAT\noaWxBPgatOVWs7RgtyGYsk+XubHkpC6f3X0+15mGhFwJ+CSE6tN+l2iF9zp52vqP\nQwkjzm7+pdhZbmaIpcq9m1K+9lqPWJRz/3XXuqi+5xWIZ7NaxGvRjqaNAoGAdK2b\nutZ2y48XoI3uPFsuP+A8kJX+CtWZrlE1NtmS7tnicdd19AtfmTuUL6fz0FwfW4Su\nlQZfPT/5B339CaEiq/Xd1kDor+J7rvUHM2+5p+1A54gMRGCLRv92FQ4EON0RC1o9\nm2I4SHysdO3XmjmdXmfp4BsgAKJIJzutvtbqlakCgYB+Cb10z37NJJ+WgjDt+yT2\nyUNH17EAYgWXryfRgTyi2POHuJitd64Xzuy6oBVs3wVveYFM6PIKXlj8/DahYX5I\nR2WIzoCNLL3bEZ+nC6Jofpb4kspoAeRporj29SgesK6QBYWHWX2H645RkRGYGpDo\n51gjy9m/hSNqBbH2zmh04A==\n-----END PRIVATE KEY-----\n",
6+
"client_email": "test-iam-credentials@dummy-project-id.iam.gserviceaccount.com",
7+
"client_id": "000000000000000000000",
8+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
9+
"token_uri": "https://oauth2.googleapis.com/token",
10+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com"
12+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
[
2+
{
3+
"description": "Simple GET",
4+
"bucket": "test-bucket",
5+
"object": "test-object",
6+
"method": "GET",
7+
"expiration": 10,
8+
"timestamp": "20190201T090000Z",
9+
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=95e6a13d43a1d1962e667f17397f2b80ac9bdd1669210d5e08e0135df9dff4e56113485dbe429ca2266487b9d1796ebdee2d7cf682a6ef3bb9fbb4c351686fba90d7b621cf1c4eb1fdf126460dd25fa0837dfdde0a9fd98662ce60844c458448fb2b352c203d9969cb74efa4bdb742287744a4f2308afa4af0e0773f55e32e92973619249214b97283b2daa14195244444e33f938138d1e5f561088ce8011f4986dda33a556412594db7c12fc40e1ff3f1bedeb7a42f5bcda0b9567f17f65855f65071fabb88ea12371877f3f77f10e1466fff6ff6973b74a933322ff0949ce357e20abe96c3dd5cfab42c9c83e740a4d32b9e11e146f0eb3404d2e975896f74"
10+
},
11+
12+
{
13+
"description": "Simple PUT",
14+
"bucket": "test-bucket",
15+
"object": "test-object",
16+
"method": "PUT",
17+
"expiration": 10,
18+
"timestamp": "20190201T090000Z",
19+
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=8adff1d4285739e31aa68e73767a46bc5511fde377497dbe08481bf5ceb34e29cc9a59921748d8ec3dd4085b7e9b7772a952afedfcdaecb3ae8352275b8b7c867f204e3db85076220a3127a8a9589302fc1181eae13b9b7fe41109ec8cdc93c1e8bac2d7a0cc32a109ca02d06957211326563ab3d3e678a0ba296e298b5fc5e14593c99d444c94724cc4be97015dbff1dca377b508fa0cb7169195de98d0e4ac96c42b918d28c8d92d33e1bd125ce0fb3cd7ad2c45dae65c22628378f6584971b8bf3945b26f2611eb651e9b6a8648970c1ecf386bb71327b082e7296c4e1ee2fc0bdd8983da80af375c817fb1ad491d0bc22c0f51dba0d66e2cffbc90803e47"
20+
},
21+
22+
{
23+
"description": "POST for resumable uploads",
24+
"bucket": "test-bucket",
25+
"object": "test-object",
26+
"method": "POST",
27+
"expiration": 10,
28+
"headers": {
29+
"x-goog-resumable": "start"
30+
},
31+
"timestamp": "20190201T090000Z",
32+
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host%3Bx-goog-resumable&X-Goog-Signature=4a6d39b23343cedf4c30782aed4b384001828c79ffa3a080a481ea01a640dea0a0ceb58d67a12cef3b243c3f036bb3799c6ee88e8db3eaf7d0bdd4b70a228d0736e07eaa1ee076aff5c6ce09dff1f1f03a0d8ead0d2893408dd3604fdabff553aa6d7af2da67cdba6790006a70240f96717b98f1a6ccb24f00940749599be7ef72aaa5358db63ddd54b2de9e2d6d6a586eac4fe25f36d86fc6ab150418e9c6fa01b732cded226c6d62fc95b72473a4cc55a8257482583fe66d9ab6ede909eb41516a8690946c3e87b0f2052eb0e97e012a14b2f721c42e6e19b8a1cd5658ea36264f10b9b1ada66b8ed5bf7ed7d1708377ac6e5fe608ae361fb594d2e5b24c54"
33+
},
34+
35+
{
36+
"description": "Vary expiration and timestamp",
37+
"bucket": "test-bucket",
38+
"object": "test-object",
39+
"method": "GET",
40+
"expiration": 20,
41+
"timestamp": "20190301T090000Z",
42+
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190301%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190301T090000Z&X-Goog-Expires=20&X-Goog-SignedHeaders=host&X-Goog-Signature=9669ed5b10664dc594c758296580662912cf4bcc5a4ba0b6bf055bcbf6f34eed7bdad664f534962174a924741a0c273a4f67bc1847cef20192a6beab44223bd9d4fbbd749c407b79997598c30f82ddc269ff47ec09fa3afe74e00616d438df0d96a7d8ad0adacfad1dc3286f864d924fe919fb0dce45d3d975c5afe8e13af2db9cc37ba77835f92f7669b61e94c6d562196c1274529e76cfff1564cc2cad7d5387dc8e12f7a5dfd925685fe92c30b43709eee29fa2f66067472cee5423d1a3a4182fe8cea75c9329d181dc6acad7c393cd04f8bf5bc0515127d8ebd65d80c08e19ad03316053ea60033fd1b1fd85a69c576415da3bf0a3718d9ea6d03e0d66f0"
43+
},
44+
45+
{
46+
"description": "Vary bucket and object",
47+
"bucket": "test-bucket2",
48+
"object": "test-object2",
49+
"method": "GET",
50+
"expiration": 10,
51+
"timestamp": "20190201T090000Z",
52+
"expectedUrl": "https://storage.googleapis.com/test-bucket2/test-object2?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=36e3d58dfd3ec1d2dd2f24b5ee372a71e811ffaa2162a2b871d26728d0354270bc116face87127532969c4a3967ed05b7309af741e19c7202f3167aa8c2ac420b61417d6451442bb91d7c822cd17be8783f01e05372769c88913561d27e6660dd8259f0081a71f831be6c50283626cbf04494ac10c394b29bb3bce74ab91548f58a37118a452693cf0483d77561fc9cac8f1765d2c724994cca46a83517a10157ee0347a233a2aaeae6e6ab5e204ff8fc5f54f90a3efdb8301d9fff5475d58cd05b181affd657f48203f4fb133c3a3d355b8eefbd10d5a0a5fd70d06e9515460ad74e22334b2cba4b29cae4f6f285cdb92d8f3126d7a1479ca3bdb69c207d860"
53+
},
54+
55+
{
56+
"description": "Simple headers",
57+
"bucket": "test-bucket",
58+
"object": "test-object",
59+
"headers": {
60+
"foo": "foo-value",
61+
"BAR": "BAR-value"
62+
},
63+
"method": "GET",
64+
"expiration": 10,
65+
"timestamp": "20190201T090000Z",
66+
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=bar%3Bfoo%3Bhost&X-Goog-Signature=68ecd3b008328ed30d91e2fe37444ed7b9b03f28ed4424555b5161980531ef87db1c3a5bc0265aad5640af30f96014c94fb2dba7479c41bfe1c020eb90c0c6d387d4dd09d4a5df8b60ea50eb6b01cdd786a1e37020f5f95eb8f9b6cd3f65a1f8a8a65c9fcb61ea662959efd9cd73b683f8d8804ef4d6d9b2852419b013368842731359d7f9e6d1139032ceca75d5e67cee5fd0192ea2125e5f2955d38d3d50cf116f3a52e6a62de77f6207f5b95aaa1d7d0f8a46de89ea72e7ea30f21286318d7eba0142232b0deb3a1dc9e1e812a981c66b5ffda3c6b01a8a9d113155792309fd53a3acfd054ca7776e8eec28c26480cd1e3c812f67f91d14217f39a606669d"
67+
},
68+
69+
{
70+
"description": "Headers should be trimmed",
71+
"bucket": "test-bucket",
72+
"object": "test-object",
73+
"headers": {
74+
"leading": " xyz",
75+
"trailing": "abc ",
76+
"collapsed": "abc def"
77+
},
78+
"method": "GET",
79+
"expiration": 10,
80+
"timestamp": "20190201T090000Z",
81+
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=collapsed%3Bhost%3Bleading%3Btrailing&X-Goog-Signature=1839511d6238d9ac2bbcbba8b23515b3757db35dfa7b8f9bc4b8b4aa270224df747c812526f1a3bcf294d67ed84cd14e074c36bc090e0a542782934a7c925af4a5ea68123e97533704ce8b08ccdf5fe6b412f89c9fc4de243e29abdb098382c5672188ee3f6fef7131413e252c78e7a35658825ad842a50609e9cc463731e17284ff7a14824c989f87cef22fb99dfec20cfeed69d8b3a08f00b43b8284eecd535e50e982b05cd74c5750cd5f986cfc21a2a05f7f3ab7fc31bd684ed1b823b64d29281e923fc6580c49005552ca19c253de087d9d2df881144e44eda40965cfdb4889bf3a35553c9809f4ed20b8355be481b92b9618952b6a04f3017b36053e15"
82+
},
83+
84+
{
85+
"description": "Header value with multiple inline values",
86+
"bucket": "test-bucket",
87+
"object": "test-object",
88+
"headers": {
89+
"multiple": " xyz , abc, def , xyz "
90+
},
91+
"method": "GET",
92+
"expiration": 10,
93+
"timestamp": "20190201T090000Z",
94+
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host%3Bmultiple&X-Goog-Signature=5cc113735625341f59c7203f0c2c9febc95ba6af6b9c38814f8e523214712087dc0996e4960d273ae1889f248ac1e58d4d19cb3a69ad7670e9a8ca1b434e878f59339dc7006cf32dfd715337e9f593e0504371839174962a08294586e0c78160a7aa303397888c8350637c6af3b32ac310886cc4590bfda9ca561ee58fb5b8ec56bc606d2ada6e7df31f4276e9dcb96bcaea39dc2cd096f3fad774f9c4b30e317ad43736c05f76831437f44e8726c1e90d3f6c9827dc273f211f32fc85658dfc5d357eb606743a6b00a29e519eef1bebaf9db3e8f4b1f5f9afb648ad06e60bc42fa8b57025056697c874c9ea76f5a73201c9717ea43e54713ff3502ff3fc626b"
95+
},
96+
97+
{
98+
"description": "Customer-supplied encryption key",
99+
"bucket": "test-bucket",
100+
"object": "test-object",
101+
"headers":
102+
{
103+
"X-Goog-Encryption-Key": "key",
104+
"X-Goog-Encryption-Key-Sha256": "key-hash",
105+
"X-Goog-Encryption-Algorithm": "AES256"
106+
},
107+
"method": "GET",
108+
"expiration": 10,
109+
"timestamp": "20190201T090000Z",
110+
"expectedUrl": "https://storage.googleapis.com/test-bucket/test-object?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host%3Bx-goog-encryption-algorithm%3Bx-goog-encryption-key%3Bx-goog-encryption-key-sha256&X-Goog-Signature=278a1c5a3bad248637054a047014760353942433955871031ed08f515b54588654ad033e91f046ab202b68673030e117d1b786c325e870238b035ba75b3feed560a17aff9bab6bddebd4a31a52cb68b214e27d3b0bd886502c6b36b164306fe88b5a07c6063592afe746b2a5d205dbe90dd5386b94f0a78f75d9f53ee884e18f476e8fc2eb1dd910ce0b4ae1f5d7b09876ef9bf983f539c028429e14bad3c75dbd4ed1ae37856f6d6f8a1805eaf8b52a0d6fc993902e4c1ee8de477661f7b67c3663000474cb00e178189789b2a3ed6bd21b4ade684fca8108ac4dd106acb17f5954d045775f7aa5a98ebda5d3075e11a8ea49c64c6ad1481e463e8c9f11f704"
111+
},
112+
113+
{
114+
"description": "List Objects",
115+
"bucket": "test-bucket",
116+
"object": "",
117+
"method": "GET",
118+
"expiration": 10,
119+
"timestamp": "20190201T090000Z",
120+
"expectedUrl": "https://storage.googleapis.com/test-bucket/?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=test-iam-credentials%40dummy-project-id.iam.gserviceaccount.com%2F20190201%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20190201T090000Z&X-Goog-Expires=10&X-Goog-SignedHeaders=host&X-Goog-Signature=2a1d342f11ddf0c90c669b9ba89ab5099f94049a86351cacbc85845fd5a8b31e1f9c8d484926c19fbd6930da6c8d3049ca8ebcfeefb7b02e53137755d36f97baab479414528b2802f10d94541facb888edf886d91ba124e60cb3801464f61aadc575fc921c99cf8c52e281f7bc0d3e740f529201c469c8e52775b6433687e0c0dca1c6b874614c3c3d09599be1e192c40ad6827416e387bf6e88a5f501f1d8225bce498d134599d0dfe30c9c833c244d3f90cf9595b9f8175658b788ee5c4a90b575fde5e83c645772250c7098373ca754b39d0fc1ebca2f50261a015931541c9827920eba67a1c41613853a1bd23299a1f9f5d583c0feb05ea2f792ba390d27"
121+
}
122+
]
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*!
2+
* Copyright 2019 Google LLC. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import * as assert from 'assert';
17+
import * as dateFormat from 'date-and-time';
18+
import * as fs from 'fs';
19+
import {OutgoingHttpHeaders} from 'http';
20+
import * as path from 'path';
21+
import * as sinon from 'sinon';
22+
23+
import {Storage} from '../src/';
24+
25+
interface V4SignedURLConformanceTestCases {
26+
description: string;
27+
bucket: string;
28+
object: string;
29+
headers?: OutgoingHttpHeaders;
30+
method: string;
31+
expiration: number;
32+
timestamp: string;
33+
expectedUrl: string;
34+
}
35+
36+
interface MethodAction {
37+
[key: string]: 'read'|'resumable'|'write'|'delete';
38+
}
39+
40+
const testFile = fs.readFileSync(
41+
path.join(
42+
__dirname,
43+
'../../conformance-test/test-data/v4SignedUrl.json',
44+
),
45+
'utf-8');
46+
47+
const testCases = JSON.parse(testFile) as V4SignedURLConformanceTestCases[];
48+
49+
const SERVICE_ACCOUNT = path.join(
50+
__dirname, '../../conformance-test/fixtures/signing-service-account.json');
51+
52+
describe('v4 signed url', () => {
53+
const storage = new Storage({keyFilename: SERVICE_ACCOUNT});
54+
55+
testCases.forEach((testCase) => {
56+
it(testCase.description, async function() {
57+
// v4 signed URL does not support Bucket operations (list bucket, etc) yet
58+
// Remove this conditional once it is supported.
59+
if (!testCase.object) {
60+
this.skip();
61+
return;
62+
}
63+
64+
const NOW =
65+
dateFormat.parse(testCase.timestamp, 'YYYYMMDD HHmmss ', true);
66+
const fakeTimer = sinon.useFakeTimers(NOW);
67+
68+
const bucket = storage.bucket(testCase.bucket);
69+
const file = bucket.file(testCase.object);
70+
71+
const action = ({
72+
GET: 'read',
73+
POST: 'resumable',
74+
PUT: 'write',
75+
DELETE: 'delete',
76+
} as MethodAction)[testCase.method];
77+
78+
const expires = NOW.valueOf() + testCase.expiration * 1000;
79+
80+
const [signedUrl] = await file.getSignedUrl({
81+
version: 'v4',
82+
action,
83+
expires,
84+
extensionHeaders: testCase.headers,
85+
});
86+
87+
assert.strictEqual(signedUrl, testCase.expectedUrl);
88+
fakeTimer.restore();
89+
});
90+
});
91+
});

handwritten/storage/package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
"scripts": {
3333
"predocs": "npm run compile",
3434
"docs": "jsdoc -c .jsdoc.js",
35+
"system-test": "mocha build/system-test --timeout 600000 && npm run conformance-test",
36+
"conformance-test": "mocha build/conformance-test",
37+
"preconformance-test": "npm run compile",
3538
"system-test": "mocha build/system-test --timeout 600000",
3639
"presystem-test": "npm run compile",
3740
"test": "nyc mocha build/test",
@@ -55,6 +58,7 @@
5558
"async": "^2.0.1",
5659
"compressible": "^2.0.12",
5760
"concat-stream": "^2.0.0",
61+
"date-and-time": "^0.6.3",
5862
"duplexify": "^3.5.0",
5963
"extend": "^3.0.0",
6064
"gcs-resumable-upload": "^1.0.0",
@@ -76,6 +80,7 @@
7680
"@types/compressible": "^2.0.0",
7781
"@types/concat-stream": "^1.6.0",
7882
"@types/configstore": "^4.0.0",
83+
"@types/date-and-time": "^0.6.0",
7984
"@types/extend": "^3.0.0",
8085
"@types/mime": "^2.0.0",
8186
"@types/mime-types": "^2.1.0",
@@ -86,6 +91,7 @@
8691
"@types/proxyquire": "^1.3.28",
8792
"@types/pumpify": "^1.4.1",
8893
"@types/request": "^2.47.1",
94+
"@types/sinon": "^7.0.10",
8995
"@types/through2": "^2.0.33",
9096
"@types/tmp": "0.1.0",
9197
"@types/uuid": "^3.4.4",
@@ -108,6 +114,7 @@
108114
"power-assert": "^1.4.4",
109115
"prettier": "^1.7.0",
110116
"proxyquire": "^2.0.0",
117+
"sinon": "^7.3.0",
111118
"source-map-support": "^0.5.6",
112119
"tmp": "^0.1.0",
113120
"typescript": "~3.4.0",

0 commit comments

Comments
 (0)