From 93a32515fc77139bd6048cdaa8680517f84e76d7 Mon Sep 17 00:00:00 2001 From: Peter Mescalchin Date: Sat, 20 Apr 2024 13:24:57 +1000 Subject: [PATCH] Added path validity checks to `setOriginCustom()/setOriginS3()` methods --- lib.js | 58 ++++++++++++++++++++++++-------------- main.js | 4 +-- test/main-property.test.js | 15 ++++++---- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/lib.js b/lib.js index 8b60715..8d907f3 100644 --- a/lib.js +++ b/lib.js @@ -232,12 +232,22 @@ function buildEventBase(eventType,hasOrigin,hasResponse) { } function setEdgeEventOriginCustom(event,domainName,path) { + // verify custom origin path + path = (path || ''); + if (!isValidOriginPath(path)) { + throw new Error(`custom origin path must be empty or begin, but not end with forward slash - got [${path}]`); + } + + if (path.length > 255) { + throw new Error(`custom origin path length must not exceed 255 characters - got [${path}]`); + } + cfEventData(event).request.origin = { custom: { customHeaders: {}, domainName: domainName, keepaliveTimeout: 1, - path: (path || ''), + path: path, port: 443, protocol: 'https', readTimeout: 4, @@ -282,12 +292,18 @@ function setEdgeEventOriginSslProtocolList(event,protocolList) { } function setEdgeEventOriginS3(event,domainName,region,path) { + // verify S3 origin path + path = (path || ''); + if (!isValidOriginPath(path)) { + throw new Error(`s3 origin path must be empty or begin, but not end with forward slash - got [${path}]`); + } + cfEventData(event).request.origin = { s3: { authMethod: 'none', customHeaders: {}, domainName: domainName, - path: (path || ''), + path: path, region: (region || ''), }, }; @@ -456,23 +472,6 @@ function payloadVerifyRequest(payload) { } function payloadVerifyRequestOrigin(payload) { - function isValidPath(path) { - if (path === '') { - return true; - } - - if (path === '/') { - return false; - } - - // invalid path if not begin with forward slash, or ending with one - if ((path[0] !== '/') || (path.slice(-1) === '/')) { - return false; - } - - return true; - } - payloadPropertyExistsObject(payload,'origin'); const origin = payload.origin; @@ -510,7 +509,7 @@ function payloadVerifyRequestOrigin(payload) { } // ensure `origin.custom.path` is valid - if (!isValidPath(custom.path)) { + if (!isValidOriginPath(custom.path)) { throw new Error(`payload property [origin.custom.path] must be empty or begin, but not end with forward slash - got [${custom.path}]`); } @@ -569,7 +568,7 @@ function payloadVerifyRequestOrigin(payload) { } // ensure `origin.s3.path` is valid - if (!isValidPath(s3.path)) { + if (!isValidOriginPath(s3.path)) { throw new Error(`payload property [origin.s3.path] must be empty or begin, but not end with forward slash - got [${s3.path}]`); } } @@ -676,6 +675,23 @@ function payloadPropertyDisplay(property,prefix) { return (prefix) ? `${prefix}.${property}` : property; } +function isValidOriginPath(path) { + if (path === '') { + return true; + } + + if (path === '/') { + return false; + } + + // invalid path if not begin with forward slash, or ending with one + if ((path[0] !== '/') || (path.slice(-1) === '/')) { + return false; + } + + return true; +} + function cfEventData(event) { return event.Records[0].cf; } diff --git a/main.js b/main.js index de4aa5b..f7ec486 100644 --- a/main.js +++ b/main.js @@ -18,7 +18,7 @@ class OriginRequest extends lib.EdgeEventRequestBase { super('origin-request',true); } - // [set|add]Origin*() methods shared by `OriginRequest` / `OriginResponse` + // [set|add]Origin*() methods shared by `OriginRequest`/`OriginResponse` setOriginCustom(domainName,path) { lib.setEdgeEventOriginCustom(this._event,domainName,path); return this; @@ -80,7 +80,7 @@ class OriginResponse extends lib.EdgeEventResponseBase { super('origin-response',true); } - // [set|add]Origin*() methods shared by `OriginRequest` / `OriginResponse` + // [set|add]Origin*() methods shared by `OriginRequest`/`OriginResponse` setOriginCustom(domainName,path) { lib.setEdgeEventOriginCustom(this._event,domainName,path); return this; diff --git a/test/main-property.test.js b/test/main-property.test.js index 5ac3a2e..06a3815 100644 --- a/test/main-property.test.js +++ b/test/main-property.test.js @@ -311,7 +311,7 @@ function testPropertyRequestOrigin(inst) { assert.deepEqual(cfEventData(inst).request.origin,{}); - // calling custom/S3 origin methods before origin mode set should throw error + // calling any custom/S3 origin methods before origin mode set should throw error throwsOriginModeCustom(function() { inst.setOriginKeepaliveTimeout(666); }); throwsOriginModeCustom(function() { inst.setOriginPort(123); }); throwsOriginModeCustom(function() { inst.setOriginHttps(); }); @@ -341,11 +341,14 @@ function testPropertyRequestOrigin(inst) { inst.setOriginCustom('my-hostname.tld','/my/path'); assert.equal(cfEventData(inst).request.origin.custom.path,'/my/path'); + assert.throws(function() { inst.setOriginCustom('my-hostname.tld','invalid/path'); }); + assert.throws(function() { inst.setOriginCustom('my-hostname.tld','/invalid/path/'); }); + assert.throws(function() { inst.setOriginCustom('my-hostname.tld','/path/too/long'.repeat(20)); }); inst - .addOriginHttpHeader('User-Agent','curl/7.x.x') .addOriginHttpHeader('Multi-Origin-Key','apples') .addOriginHttpHeader('Multi-Origin-Key','oranges') + .addOriginHttpHeader('User-Agent','curl/7.x.x') .addOriginHttpHeader('X-Remove-Me','banana'); assert.deepEqual(cfEventData(inst).request.origin.custom.customHeaders, @@ -426,7 +429,7 @@ function testPropertyRequestOrigin(inst) { // test: origin [S3] - inst.setOriginS3('my-bucket.s3.ap-southeast-2.amazonaws.com'); // note: `path` defaults to empty string + inst.setOriginS3('my-bucket.s3.ap-southeast-2.amazonaws.com'); // note: `region` and `path` defaults to empty string assert.deepEqual(cfEventData(inst).request.origin, { s3: { @@ -445,11 +448,13 @@ function testPropertyRequestOrigin(inst) { inst.setOriginS3('my-bucket.s3.ap-southeast-2.amazonaws.com','ap-southeast-2','/my/path'); assert.equal(cfEventData(inst).request.origin.s3.path,'/my/path'); assert.equal(cfEventData(inst).request.origin.s3.region,'ap-southeast-2'); + assert.throws(function() { inst.setOriginS3('my-bucket.s3.ap-southeast-2.amazonaws.com','ap-southeast-2','invalid/path'); }); + assert.throws(function() { inst.setOriginS3('my-bucket.s3.ap-southeast-2.amazonaws.com','ap-southeast-2','/invalid/path/'); }); inst - .addOriginHttpHeader('User-Agent','curl/7.x.x') .addOriginHttpHeader('Multi-Origin-Key','apples') - .addOriginHttpHeader('Multi-Origin-Key','oranges'); + .addOriginHttpHeader('Multi-Origin-Key','oranges') + .addOriginHttpHeader('User-Agent','curl/7.x.x'); assert.deepEqual(cfEventData(inst).request.origin.s3.customHeaders, {