Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 83 additions & 74 deletions dist/common/processURL.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProcessURL = void 0;
var query_string_1 = __importDefault(require("query-string"));
var logger_1 = require("./logger");
var ProcessURL = /** @class */ (function () {
function ProcessURL(request, debug) {
Expand Down Expand Up @@ -35,88 +31,101 @@ var ProcessURL = /** @class */ (function () {
specialParameters: this.specialParameters,
};
}
//Extract query string from this.path
function extractQueryString(path) {
var queryString;
if (path.includes("?")) {
queryString = path.split("?")[1];
}
return queryString;
}
function formatQueryString(q) {
if (q) {
return query_string_1.default.parse(q, { sort: false });
}
}
var unprocessedQueryString;
unprocessedQueryString = extractQueryString(this.path);
if (unprocessedQueryString) {
this.queryString = formatQueryString(unprocessedQueryString);
}
//Destructure special params from query string if they are present
var _a = this.queryString || {}, chCode = _a["ch-code"], chID = _a["ch-id"], chIDSignature = _a["ch-id-signature"], chPublicKey = _a["ch-public-key"], chRequested = _a["ch-requested"];
//Override chCode value if the current one is unusable
if (!chCode || chCode === "undefined" || chCode === "null") {
chCode = "";
}
this.specialParameters.chCode = chCode;
//Override chID value if the current one is unusable
if (!chID || chID === "undefined" || chID === "null") {
chID = "";
}
this.specialParameters.chID = chID;
//Override chIDSignature value if the current one is unusable
if (!chIDSignature ||
chIDSignature === "undefined" ||
chIDSignature === "null") {
chIDSignature = "";
}
this.specialParameters.chIDSignature = chIDSignature;
//Override chPublicKey value if the current one is unusable
if (!chPublicKey || chPublicKey === "undefined" || chPublicKey === "null") {
chPublicKey = "";
// Extract raw query string from path (preserving original encoding)
if (this.path.includes("?")) {
this.rawQueryString = this.path.split("?")[1];
}
this.specialParameters.chPublicKey = chPublicKey;
//Override chRequested value if the current one is unusable
if (!chRequested || chRequested === "undefined" || chRequested === "null") {
chRequested = "";
}
this.specialParameters.chRequested = chRequested;
// Process the query string
var processedQueryString = this.processQueryString(this.queryString);
//URL encode the targetURL to be used later in redirects
var targetURL;
//We no longer need the query string in the path
this.path = this.path.split("?")[0];
// Extract ch-* parameter values using regex (decode for actual use)
var chCode = this.extractParamValue("ch-code");
var chID = this.extractParamValue("ch-id");
var chIDSignature = this.extractParamValue("ch-id-signature");
var chPublicKey = this.extractParamValue("ch-public-key");
var chRequested = this.extractParamValue("ch-requested");
// Set special parameters (with validation)
this.specialParameters.chCode = this.sanitizeParam(chCode);
this.specialParameters.chID = this.sanitizeParam(chID);
this.specialParameters.chIDSignature = this.sanitizeParam(chIDSignature);
this.specialParameters.chPublicKey = this.sanitizeParam(chPublicKey);
this.specialParameters.chRequested = this.sanitizeParam(chRequested);
// Remove ch-* params from query string while preserving everything else
var processedQueryString = this.removeChParams(this.rawQueryString);
// Extract path without query string
var cleanPath = this.path.split("?")[0];
// Construct targetURL
if (processedQueryString) {
this.targetURL = encodeURIComponent("https://".concat(this.host).concat(this.path, "?").concat(processedQueryString));
this.targetURL = encodeURIComponent("https://".concat(this.host).concat(cleanPath, "?").concat(processedQueryString));
}
else {
this.targetURL = encodeURIComponent("https://".concat(this.host).concat(this.path));
this.targetURL = encodeURIComponent("https://".concat(this.host).concat(cleanPath));
}
return {
targetURL: this.targetURL,
specialParameters: this.specialParameters,
};
};
ProcessURL.prototype.processQueryString = function (queryString) {
var processedQueryString;
if (queryString) {
delete queryString["ch-code"];
delete queryString["ch-fresh"];
delete queryString["ch-id"];
delete queryString["ch-id-signature"];
delete queryString["ch-public-key"];
delete queryString["ch-requested"];
}
//Convert to usable querystring format
if (queryString && Object.keys(queryString).length !== 0) {
processedQueryString = query_string_1.default.stringify(queryString, { sort: false });
/**
* Extract a parameter value from the raw query string using regex.
* Decodes the value for actual use.
*
* Treats `+` as a space before percent-decoding — this is the HTML
* form-encoding convention used by URLSearchParams and the legacy
* query-string library, and by every other CrowdHandler integration
* (Cloudflare Worker, CloudFront). `decodeURIComponent` alone does not
* do this. Keeping it consistent matters for signature validation: any
* divergence in how the SDK and the edge decode ch-* values produces
* mismatched signatures.
*/
ProcessURL.prototype.extractParamValue = function (paramName) {
if (!this.rawQueryString)
return "";
// Match the parameter in the query string
var regex = new RegExp("(?:^|&)".concat(paramName, "=([^&]*)"), "i");
var match = this.rawQueryString.match(regex);
if (match && match[1]) {
var normalized = match[1].replace(/\+/g, "%20");
try {
return decodeURIComponent(normalized);
}
catch (_a) {
// Malformed percent-encoding. Still honour the `+` → space convention
// on the fallback path so output stays consistent with URLSearchParams.
return match[1].replace(/\+/g, " ");
}
}
else {
processedQueryString = "";
return "";
};
/**
* Sanitize a parameter value - return empty string for unusable values.
*/
ProcessURL.prototype.sanitizeParam = function (value) {
if (!value || value === "undefined" || value === "null") {
return "";
}
return processedQueryString;
return value;
};
/**
* Remove ch-* parameters from the query string while preserving
* the original encoding of all other parameters.
*/
ProcessURL.prototype.removeChParams = function (queryString) {
if (!queryString)
return "";
// List of ch-* parameters to remove
var chParams = [
"ch-code",
"ch-fresh",
"ch-id",
"ch-id-signature",
"ch-public-key",
"ch-requested",
];
// Split into individual params, filter out ch-* params, rejoin
var params = queryString.split("&");
var filteredParams = params.filter(function (param) {
var key = param.split("=")[0];
return !chParams.includes(key.toLowerCase());
});
return filteredParams.join("&");
};
return ProcessURL;
}());
Expand Down
12 changes: 1 addition & 11 deletions dist/common/types.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Modes = exports.RecordPerformanceOptions = exports.SessionStatusWrapper = exports.HttpErrorWrapper = exports.ValidateRequestObject = exports.ValidateRequestParams = exports.TokenObjectConstructor = exports.TokenObject = exports.ExtractTokenOptions = exports.SignatureSourceObject = exports.SignatureResponseObject = exports.SignatureObject = exports.RoomMetaObject = exports.LocalStorageOptions = exports.LocalStorageObject = exports.CookieObject = exports.RequestObject = exports.ProcessURLResultObject = exports.SessionRequestConfig = exports.SpecialParametersObject = exports.QueryObject = exports.GatekeeperKeyPair = exports.GatekeeperOptions = exports.RoomsConfig = exports.RoomConfig = void 0;
exports.Modes = exports.RecordPerformanceOptions = exports.SessionStatusWrapper = exports.HttpErrorWrapper = exports.ValidateRequestObject = exports.ValidateRequestParams = exports.TokenObjectConstructor = exports.TokenObject = exports.ExtractTokenOptions = exports.SignatureSourceObject = exports.SignatureResponseObject = exports.SignatureObject = exports.RoomMetaObject = exports.LocalStorageOptions = exports.LocalStorageObject = exports.CookieObject = exports.RequestObject = exports.ProcessURLResultObject = exports.SessionRequestConfig = exports.SpecialParametersObject = exports.GatekeeperKeyPair = exports.GatekeeperOptions = exports.RoomsConfig = exports.RoomConfig = void 0;
var zod_1 = require("zod");
// Lite Validator types
exports.RoomConfig = zod_1.z.object({
Expand Down Expand Up @@ -32,16 +32,6 @@ exports.GatekeeperKeyPair = zod_1.z.object({
publicKey: zod_1.z.string(),
privateKey: zod_1.z.string().optional(),
});
exports.QueryObject = zod_1.z
.object({
"ch-code": zod_1.z.string().optional(),
"ch-id": zod_1.z.string().optional(),
"ch-id-signature": zod_1.z.string().optional(),
"ch-public-key": zod_1.z.string().optional(),
"ch-requested": zod_1.z.string().optional(),
"ch-token": zod_1.z.string().optional(),
})
.catchall(zod_1.z.any());
exports.SpecialParametersObject = zod_1.z.object({
chCode: zod_1.z.string(),
chID: zod_1.z.string(),
Expand Down
Loading