diff --git a/CHANGELOG.md b/CHANGELOG.md index d249c82..709e57b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.2.2 — 2026-10-30 + +Fixes the Shotstack credential in n8n's HTTP Request node. With the credential +picked there, calls to api.shotstack.io (such as the Ingest API) went out without +the API key and failed with "Missing API key". The key still only goes to +api.shotstack.io. + ## 0.2.1 — 2026-10-07 Adds search words, so n8n's Nodes panel finds Shotstack when people search for diff --git a/credentials/ShotstackApi.credentials.ts b/credentials/ShotstackApi.credentials.ts index fe61c88..ab545ee 100644 --- a/credentials/ShotstackApi.credentials.ts +++ b/credentials/ShotstackApi.credentials.ts @@ -69,7 +69,10 @@ export class ShotstackApi implements ICredentialType { // relative url like //evil.example.com/x is absolute to axios but not to // /^https?:\/\//, so that test fell through to baseURL, saw Shotstack and // attached the key to a request axios then sent to evil.example.com. - const url = String(requestOptions.url ?? ''); + // + // n8n's HTTP Request node still goes through the legacy request helper, + // which names the address uri, so read that too or the key never goes. + const url = String(requestOptions.url ?? (requestOptions as { uri?: string }).uri ?? ''); const target = /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url) ? url : String(requestOptions.baseURL ?? ''); diff --git a/test/credential-host-scope.mjs b/test/credential-host-scope.mjs index 5be4211..e3f8d5d 100644 --- a/test/credential-host-scope.mjs +++ b/test/credential-host-scope.mjs @@ -40,6 +40,9 @@ const cases = [ false, ], ['protocol relative url with no baseURL', { baseURL: '', url: '//evil.example.com/x.mp4' }, false], + // n8n's HTTP Request node, with this credential picked, passes uri, not url. + ['HTTP Request node to the Ingest API', { uri: 'https://api.shotstack.io/ingest/v1/sources' }, true], + ['HTTP Request node to a third party', { uri: 'https://evil.example.com/collect.mp4' }, false], // The same rule must not stop the key reaching a genuine relative call. ['a relative path on the Edit API', { baseURL: 'https://api.shotstack.io/edit/stage', url: '/render' }, true], ];