From 9d3a5b4d6d1aa161c46a71035740cab5203ec93d Mon Sep 17 00:00:00 2001 From: Zakir Abdalimov Date: Tue, 4 Mar 2025 19:33:58 +0100 Subject: [PATCH 1/4] feat: add cdn signed url sample --- .github/workflows/cdn-signed-urls.yaml | 52 ++++++++++++++++++++++++++ .github/workflows/utils/workflows.json | 1 + cdn/signed-urls/package.json | 18 +++++++++ cdn/signed-urls/signurl.js | 34 +++++++++++++++++ cdn/signed-urls/test/signurl.test.js | 25 +++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 .github/workflows/cdn-signed-urls.yaml create mode 100644 cdn/signed-urls/package.json create mode 100644 cdn/signed-urls/signurl.js create mode 100644 cdn/signed-urls/test/signurl.test.js diff --git a/.github/workflows/cdn-signed-urls.yaml b/.github/workflows/cdn-signed-urls.yaml new file mode 100644 index 0000000000..ed59e80b0a --- /dev/null +++ b/.github/workflows/cdn-signed-urls.yaml @@ -0,0 +1,52 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: cdn-signed-urls +on: + push: + branches: + - main + paths: + - 'cdn/signed-urls/**' + - '.github/workflows/cdn-signed-urls.yaml' + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + paths: + - 'cdn/signed-urls/**' + - '.github/workflows/cdn-signed-urls.yaml' + schedule: + - cron: '0 0 * * 0' +jobs: + test: + # Ref: https://github.com/google-github-actions/auth#usage + permissions: + contents: 'read' + id-token: 'write' + if: github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' + uses: ./.github/workflows/test.yaml + with: + name: 'cdn-signed-urls' + path: 'cdn/signed-urls' + flakybot: + # Ref: https://github.com/google-github-actions/auth#usage + permissions: + contents: 'read' + id-token: 'write' + if: github.event_name == 'schedule' && always() # always() submits logs even if tests fail + uses: ./.github/workflows/flakybot.yaml + needs: [test] diff --git a/.github/workflows/utils/workflows.json b/.github/workflows/utils/workflows.json index ec662d7be7..31bb7c0e4f 100644 --- a/.github/workflows/utils/workflows.json +++ b/.github/workflows/utils/workflows.json @@ -18,6 +18,7 @@ "asset/snippets", "auth", "batch", + "cdn/signed-urls", "cloudbuild", "cloud-language", "cloud-tasks/snippets", diff --git a/cdn/signed-urls/package.json b/cdn/signed-urls/package.json new file mode 100644 index 0000000000..e14a11b2c8 --- /dev/null +++ b/cdn/signed-urls/package.json @@ -0,0 +1,18 @@ +{ + "name": "signed-urls-samples", + "private": true, + "license": "Apache-2.0", + "author": "Google LLC", + "engines": { + "node": ">=16.0.0" + }, + "files": [ + "*.js" + ], + "scripts": { + "test": "mocha -p -j 2 **/*.test.js" + }, + "devDependencies": { + "mocha": "^10.0.0" + } +} \ No newline at end of file diff --git a/cdn/signed-urls/signurl.js b/cdn/signed-urls/signurl.js new file mode 100644 index 0000000000..6254ad657a --- /dev/null +++ b/cdn/signed-urls/signurl.js @@ -0,0 +1,34 @@ +'use strict'; + +// [START nodejs_cdn_signed_urls] +const crypto = require('crypto'); + +/** + * Sign url to access Google Cloud CDN resource secured by key. + * @param url the Cloud CDN endpoint to sign + * @param keyName name of the signing key configured in the backend service/bucket + * @param keyValue value of the signing key + * @param expirationDate the date that the signed URL expires + * @return signed CDN URL + */ +function signUrl(url, keyName, keyValue, expirationDate) { + const urlObject = new URL(url); + urlObject.searchParams.set( + 'Expires', + Math.floor(expirationDate.valueOf() / 1000).toString() + ); + urlObject.searchParams.set('KeyName', keyName); + + const signature = crypto + .createHmac('sha1', Buffer.from(keyValue, 'base64')) + .update(urlObject.href) + .digest('base64url'); + urlObject.searchParams.set('Signature', signature); + + return urlObject.href; +} +// [END nodejs_cdn_signed_urls] + +module.exports = { + signUrl, +}; diff --git a/cdn/signed-urls/test/signurl.test.js b/cdn/signed-urls/test/signurl.test.js new file mode 100644 index 0000000000..895b7a0194 --- /dev/null +++ b/cdn/signed-urls/test/signurl.test.js @@ -0,0 +1,25 @@ +'use strict'; + +const {signUrl} = require('../signurl'); +const assert = require('node:assert/strict'); + +describe('signUrl', () => { + it('should return signed url with corresponding parameters', () => { + const url = new URL('https://cdn.example.com/test-path'); + const keyName = 'test-key-name'; + const keyValue = '0zY26LFZ2yAa3fERaKiKDQ=='; + const expirationDate = new Date(); + + const resultUrl = new URL( + signUrl(url.href, keyName, keyValue, expirationDate) + ); + assert.strictEqual(resultUrl.hostname, url.hostname); + assert.strictEqual(resultUrl.pathname, url.pathname); + assert.strictEqual(resultUrl.searchParams.get('KeyName'), keyName); + assert.strictEqual( + resultUrl.searchParams.get('Expires'), + Math.floor(expirationDate.valueOf() / 1000).toString() + ); + assert.ok(resultUrl.searchParams.get('Signature')); + }); +}); From fbd048a6203e32b39fdc749cc0174e13cf88d31d Mon Sep 17 00:00:00 2001 From: Zakir Abdalimov Date: Tue, 4 Mar 2025 20:43:39 +0100 Subject: [PATCH 2/4] chore: add license headers to cdn signed urls snippet --- cdn/signed-urls/signurl.js | 14 ++++++++++++++ cdn/signed-urls/test/signurl.test.js | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/cdn/signed-urls/signurl.js b/cdn/signed-urls/signurl.js index 6254ad657a..3b556609df 100644 --- a/cdn/signed-urls/signurl.js +++ b/cdn/signed-urls/signurl.js @@ -1,3 +1,17 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + 'use strict'; // [START nodejs_cdn_signed_urls] diff --git a/cdn/signed-urls/test/signurl.test.js b/cdn/signed-urls/test/signurl.test.js index 895b7a0194..4d77bf82cc 100644 --- a/cdn/signed-urls/test/signurl.test.js +++ b/cdn/signed-urls/test/signurl.test.js @@ -1,3 +1,17 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + 'use strict'; const {signUrl} = require('../signurl'); From 93a02ec6a179cb6c2bcf86aaa0ecc9773d013301 Mon Sep 17 00:00:00 2001 From: Katie McLaughlin Date: Fri, 8 Aug 2025 14:36:58 +1000 Subject: [PATCH 3/4] Apply suggestions from code review --- cdn/signed-urls/signurl.js | 6 +++--- cdn/signed-urls/test/signurl.test.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cdn/signed-urls/signurl.js b/cdn/signed-urls/signurl.js index 3b556609df..729440a8f7 100644 --- a/cdn/signed-urls/signurl.js +++ b/cdn/signed-urls/signurl.js @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ 'use strict'; -// [START nodejs_cdn_signed_urls] +// [START cloudcdn_sign_url] const crypto = require('crypto'); /** @@ -41,7 +41,7 @@ function signUrl(url, keyName, keyValue, expirationDate) { return urlObject.href; } -// [END nodejs_cdn_signed_urls] +// [END cloudcdn_sign_url] module.exports = { signUrl, diff --git a/cdn/signed-urls/test/signurl.test.js b/cdn/signed-urls/test/signurl.test.js index 4d77bf82cc..f900b5c5d7 100644 --- a/cdn/signed-urls/test/signurl.test.js +++ b/cdn/signed-urls/test/signurl.test.js @@ -1,4 +1,4 @@ -// Copyright 2018 Google LLC +// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From 78f6186e1980e445036c35572b14de0ae0522d82 Mon Sep 17 00:00:00 2001 From: Katie McLaughlin Date: Fri, 8 Aug 2025 14:39:22 +1000 Subject: [PATCH 4/4] Delete .github/workflows/cdn-signed-urls.yaml No longer required due to changes in [testing](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/main/CONTRIBUTING.md#ci-testing) --- .github/workflows/cdn-signed-urls.yaml | 52 -------------------------- 1 file changed, 52 deletions(-) delete mode 100644 .github/workflows/cdn-signed-urls.yaml diff --git a/.github/workflows/cdn-signed-urls.yaml b/.github/workflows/cdn-signed-urls.yaml deleted file mode 100644 index ed59e80b0a..0000000000 --- a/.github/workflows/cdn-signed-urls.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: cdn-signed-urls -on: - push: - branches: - - main - paths: - - 'cdn/signed-urls/**' - - '.github/workflows/cdn-signed-urls.yaml' - pull_request: - types: - - opened - - reopened - - synchronize - - labeled - paths: - - 'cdn/signed-urls/**' - - '.github/workflows/cdn-signed-urls.yaml' - schedule: - - cron: '0 0 * * 0' -jobs: - test: - # Ref: https://github.com/google-github-actions/auth#usage - permissions: - contents: 'read' - id-token: 'write' - if: github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' - uses: ./.github/workflows/test.yaml - with: - name: 'cdn-signed-urls' - path: 'cdn/signed-urls' - flakybot: - # Ref: https://github.com/google-github-actions/auth#usage - permissions: - contents: 'read' - id-token: 'write' - if: github.event_name == 'schedule' && always() # always() submits logs even if tests fail - uses: ./.github/workflows/flakybot.yaml - needs: [test]