diff --git a/src/core/operations/URLEncode.mjs b/src/core/operations/URLEncode.mjs
index a5efd2135c..99eec91d7a 100644
--- a/src/core/operations/URLEncode.mjs
+++ b/src/core/operations/URLEncode.mjs
@@ -21,7 +21,7 @@ class URLEncode extends Operation {
this.module = "URL";
this.description = "Encodes problematic characters into percent-encoding, a format supported by URIs/URLs.
e.g. = becomes %3d";
this.infoURL = "https://wikipedia.org/wiki/Percent-encoding";
- this.inputType = "string";
+ this.inputType = "byteArray";
this.outputType = "string";
this.args = [
{
@@ -33,34 +33,38 @@ class URLEncode extends Operation {
}
/**
- * @param {string} input
+ * @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const encodeAll = args[0];
- return encodeAll ? this.encodeAllChars(input) : encodeURI(input);
+ return this.encodeBytes(input, encodeAll);
}
/**
- * Encode characters in URL outside of encodeURI() function spec
+ * Encode bytes in URL using percent encoding.
*
- * @param {string} str
+ * @param {byteArray} bytes
+ * @param {boolean} encodeAll
* @returns {string}
*/
- encodeAllChars (str) {
- // TODO Do this programmatically
- return encodeURIComponent(str)
- .replace(/!/g, "%21")
- .replace(/#/g, "%23")
- .replace(/'/g, "%27")
- .replace(/\(/g, "%28")
- .replace(/\)/g, "%29")
- .replace(/\*/g, "%2A")
- .replace(/-/g, "%2D")
- .replace(/\./g, "%2E")
- .replace(/_/g, "%5F")
- .replace(/~/g, "%7E");
+ encodeBytes(bytes, encodeAll) {
+ const safeChars = encodeAll ?
+ /^[A-Za-z0-9]$/ :
+ /^[A-Za-z0-9:/?#[\]@!$&'()*+,;=%]$/;
+
+ let output = "";
+
+ for (const byte of bytes) {
+ const char = String.fromCharCode(byte);
+
+ output += safeChars.test(char) ?
+ char :
+ "%" + byte.toString(16).toUpperCase().padStart(2, "0");
+ }
+
+ return output;
}
}
diff --git a/tests/operations/tests/URLEncodeDecode.mjs b/tests/operations/tests/URLEncodeDecode.mjs
index 444f76d37a..8d9d09db58 100644
--- a/tests/operations/tests/URLEncodeDecode.mjs
+++ b/tests/operations/tests/URLEncodeDecode.mjs
@@ -89,4 +89,30 @@ TestRegister.addTests([
},
],
},
+ {
+ name: "URLEncode: encodes UTF-8 text as UTF-8 bytes",
+ input: "你好",
+ expectedOutput: "%E4%BD%A0%E5%A5%BD",
+ recipeConfig: [
+ {
+ op: "URL Encode",
+ args: [false],
+ },
+ ],
+ },
+ {
+ name: "URLEncode: preserves raw bytes from From Hex",
+ input: "6c6567697466696c6580000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090746869737761737375706f736564746f6265616e6578706c6f6974",
+ expectedOutput: "legitfile%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%90thiswassuposedtobeanexploit",
+ recipeConfig: [
+ {
+ op: "From Hex",
+ args: ["None"],
+ },
+ {
+ op: "URL Encode",
+ args: [false],
+ },
+ ],
+ },
]);