diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index bebdd6a5e2..f628a83f8b 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -238,6 +238,7 @@ "Parse UDP", "Parse SSH Host Key", "Parse URI", + "Extract URI", "URL Encode", "URL Decode", "Protobuf Decode", diff --git a/src/core/operations/ExtractURI.mjs b/src/core/operations/ExtractURI.mjs new file mode 100644 index 0000000000..f2751244b3 --- /dev/null +++ b/src/core/operations/ExtractURI.mjs @@ -0,0 +1,65 @@ +/** + * @author David Tomaschik [dwt@google.com] + * @copyright Google LLC 2024 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Extract a URI to JSON Operation + */ +class ExtractURI extends Operation { + /** + * ExtractURI Constructor + */ + constructor() { + super(); + + this.name = "Extract URI"; + this.module = "URL"; + this.description = "Extract components of URI to JSON for further processing."; + this.infoURL = "https://wikipedia.org/wiki/Uniform_Resource_Identifier"; + this.inputType = "string"; + this.outputType = "JSON"; + this.args = []; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {JSON} + */ + run(input, args) { + const uri = new URL(input); + const pieces = {}; + // Straight copy some attributes + [ + "hash", + "hostname", + "password", + "pathname", + "port", + "protocol", + "username" + ].forEach((name) => { + if (uri[name]) pieces[name] = uri[name]; + }); + // Now handle query params + const params = uri.searchParams; + if (params.size) { + pieces.query = {}; + for (const name of params.keys()) { + const values = params.getAll(name); + if (values.length > 1) { + pieces.query[name] = values; + } else { + pieces.query[name] = values[0]; + } + } + } + return pieces; + } +}; + +export default ExtractURI; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 40ce7a2ee6..cc3cca82d3 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -64,6 +64,7 @@ import "./tests/ELFInfo.mjs"; import "./tests/Enigma.mjs"; import "./tests/ExtractEmailAddresses.mjs"; import "./tests/ExtractHashes.mjs"; +import "./tests/ExtractURI.mjs"; import "./tests/Float.mjs"; import "./tests/FileTree.mjs"; import "./tests/FletcherChecksum.mjs"; diff --git a/tests/operations/tests/ExtractURI.mjs b/tests/operations/tests/ExtractURI.mjs new file mode 100644 index 0000000000..bba741da84 --- /dev/null +++ b/tests/operations/tests/ExtractURI.mjs @@ -0,0 +1,36 @@ +/** + * Extract URI Tests + * + * @author David Tomaschik [dwt@google.com] + * @copyright Google LLC 2024 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Extract URI: Test", + input: "http://www.example.org:9999/path?foo=bar&baz=1&baz=2#frob", + expectedOutput: JSON.stringify({ + "hash": "#frob", + "hostname": "www.example.org", + "pathname": "/path", + "port": "9999", + "protocol": "http:", + "query": { + "foo": "bar", + "baz": [ + "1", + "2" + ] + } + }, null, 4), + recipeConfig: [ + { + "op": "Extract URI", + "args": [], + } + ] + } +]);