cyberchef 10.23.0 → 10.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @author j83305 [awz22@protonmail.com]
3
+ * @copyright Crown Copyright 2020
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import { calculateParityBit, decodeParityBit } from "../lib/ParityBit.mjs";
9
+
10
+ /**
11
+ * Parity Bit operation
12
+ */
13
+ class ParityBit extends Operation {
14
+
15
+ /**
16
+ * ParityBit constructor
17
+ */
18
+ constructor() {
19
+ super();
20
+
21
+ this.name = "Parity Bit";
22
+ this.module = "Default";
23
+ this.description = "A parity bit, or check bit, is the simplest form of error detection. It is a bit which is added to a string of bits and represents if the number of 1's in the binary string is an even number or odd number.<br><br>If a delimiter is specified, the parity bit calculation will be performed on each 'block' of the input data, where the blocks are created by slicing the input at each occurence of the delimiter character";
24
+ this.infoURL = "https://wikipedia.org/wiki/Parity_bit";
25
+ this.inputType = "string";
26
+ this.outputType = "string";
27
+ this.args = [
28
+ {
29
+ name: "Mode",
30
+ type: "option",
31
+ value: [
32
+ "Even Parity",
33
+ "Odd Parity"
34
+ ]
35
+ },
36
+ {
37
+ name: "Postion",
38
+ type: "option",
39
+ value: [
40
+ "Start",
41
+ "End"
42
+ ]
43
+ },
44
+ {
45
+ name: "Encode or Decode",
46
+ type: "option",
47
+ value: [
48
+ "Encode",
49
+ "Decode"
50
+ ]
51
+ },
52
+ {
53
+ name: "Delimiter",
54
+ type: "shortString",
55
+ value: ""
56
+ }
57
+ ];
58
+ }
59
+
60
+ /**
61
+ * @param {string} input
62
+ * @param {Object[]} args
63
+ * @returns {string}
64
+ */
65
+ run(input, args) {
66
+ if (input.length === 0) {
67
+ return input;
68
+ }
69
+ /**
70
+ * determines weather to use the encode or decode method based off args[2]
71
+ * @param input input to be encoded or decoded
72
+ * @param args array
73
+ */
74
+ const method = (input, args) => args[2] === "Encode" ? calculateParityBit(input, args) : decodeParityBit(input, args);
75
+ if (args[3].length > 0) {
76
+ const byteStrings = input.split(args[3]);
77
+ for (let byteStringsArrayIndex = 0; byteStringsArrayIndex < byteStrings.length; byteStringsArrayIndex++) {
78
+ byteStrings[byteStringsArrayIndex] = method(byteStrings[byteStringsArrayIndex], args);
79
+ }
80
+ return byteStrings.join(args[3]);
81
+ }
82
+ return method(input, args);
83
+ }
84
+
85
+ /**
86
+ * Highlight Parity Bit
87
+ *
88
+ * @param {Object[]} pos
89
+ * @param {number} pos[].start
90
+ * @param {number} pos[].end
91
+ * @param {Object[]} args
92
+ * @returns {Object[]} pos
93
+ */
94
+ highlight(pos, args) {
95
+ if (args[3].length === 0) {
96
+ if (args[1] === "Prepend") {
97
+ pos[0].start += 1;
98
+ pos[0].end += 1;
99
+ }
100
+ return pos;
101
+ }
102
+ // need to be able to read input to do the highlighting when there is a delimiter
103
+ }
104
+
105
+ /**
106
+ * Highlight Parity Bit in reverse
107
+ *
108
+ * @param {Object[]} pos
109
+ * @param {number} pos[].start
110
+ * @param {number} pos[].end
111
+ * @param {Object[]} args
112
+ * @returns {Object[]} pos
113
+ */
114
+ highlightReverse(pos, args) {
115
+ if (args[3].length === 0) {
116
+ if (args[1] === "Prepend") {
117
+ if (pos[0].start > 0) {
118
+ pos[0].start -= 1;
119
+ }
120
+ pos[0].end -= 1;
121
+ }
122
+ return pos;
123
+ }
124
+ }
125
+
126
+ }
127
+
128
+ export default ParityBit;
@@ -7,6 +7,7 @@
7
7
  import XRegExp from "xregexp";
8
8
  import Operation from "../Operation.mjs";
9
9
  import Utils from "../Utils.mjs";
10
+ import { EMAIL_REGEX } from "../lib/Extract.mjs";
10
11
  import OperationError from "../errors/OperationError.mjs";
11
12
 
12
13
  /**
@@ -45,7 +46,7 @@ class RegularExpression extends Operation {
45
46
  },
46
47
  {
47
48
  name: "Email address",
48
- value: "(?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9](?:[\\u00A0-\\uD7FF\\uE000-\\uFFFF-a-z0-9-]*[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9])?\\.)+[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9](?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9-]*[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}\\])"
49
+ value: EMAIL_REGEX.source // We use a different regex library, so just take the source regex string here
49
50
  },
50
51
  {
51
52
  name: "URL",
@@ -35,6 +35,11 @@ class RenderMarkdown extends Operation {
35
35
  name: "Enable syntax highlighting",
36
36
  type: "boolean",
37
37
  value: true
38
+ },
39
+ {
40
+ name: "Open links in new tab.",
41
+ type: "boolean",
42
+ value: false
38
43
  }
39
44
  ];
40
45
  }
@@ -45,7 +50,7 @@ class RenderMarkdown extends Operation {
45
50
  * @returns {html}
46
51
  */
47
52
  run(input, args) {
48
- const [convertLinks, enableHighlighting] = args,
53
+ const [convertLinks, enableHighlighting, openLinksBlank] = args,
49
54
  md = new MarkdownIt({
50
55
  linkify: convertLinks,
51
56
  html: false, // Explicitly disable HTML rendering
@@ -58,12 +63,38 @@ class RenderMarkdown extends Operation {
58
63
 
59
64
  return "";
60
65
  }
61
- }),
62
- rendered = md.render(input);
63
-
66
+ });
67
+ if (openLinksBlank) {
68
+ this.makeLinksOpenInNewTab(md);
69
+ }
70
+ const rendered = md.render(input);
64
71
  return `<div style="font-family: var(--primary-font-family)">${rendered}</div>`;
65
72
  }
66
73
 
74
+ /**
75
+ * Adds target="_blank" to links.
76
+ * @param {MarkdownIt} md
77
+ */
78
+ makeLinksOpenInNewTab(md) {
79
+ // Adapted from: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
80
+ // Remember old renderer, if overridden, or proxy to default renderer
81
+ const defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
82
+ return self.renderToken(tokens, idx, options);
83
+ };
84
+
85
+ // eslint-disable-next-line camelcase
86
+ md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
87
+ const token = tokens[idx];
88
+ if (token.attrIndex("target") >= 0) {
89
+ // Target attribute already set, do not replace.
90
+ return;
91
+ }
92
+ token.attrPush(["target", "_blank"]); // add new attribute
93
+
94
+ // pass token to default renderer.
95
+ return defaultRender(tokens, idx, options, env, self);
96
+ };
97
+ }
67
98
  }
68
99
 
69
100
  export default RenderMarkdown;
@@ -288,6 +288,7 @@ import PHPDeserialize from "./PHPDeserialize.mjs";
288
288
  import PHPSerialize from "./PHPSerialize.mjs";
289
289
  import PLISTViewer from "./PLISTViewer.mjs";
290
290
  import PadLines from "./PadLines.mjs";
291
+ import ParityBit from "./ParityBit.mjs";
291
292
  import ParseASN1HexString from "./ParseASN1HexString.mjs";
292
293
  import ParseCSR from "./ParseCSR.mjs";
293
294
  import ParseColourCode from "./ParseColourCode.mjs";
@@ -765,6 +766,7 @@ export {
765
766
  PHPSerialize,
766
767
  PLISTViewer,
767
768
  PadLines,
769
+ ParityBit,
768
770
  ParseASN1HexString,
769
771
  ParseCSR,
770
772
  ParseColourCode,
@@ -289,6 +289,7 @@ import {
289
289
  PHPSerialize as core_PHPSerialize,
290
290
  PLISTViewer as core_PLISTViewer,
291
291
  PadLines as core_PadLines,
292
+ ParityBit as core_ParityBit,
292
293
  ParseASN1HexString as core_ParseASN1HexString,
293
294
  ParseCSR as core_ParseCSR,
294
295
  ParseColourCode as core_ParseColourCode,
@@ -766,6 +767,7 @@ function generateChef() {
766
767
  "PHPSerialize": _wrap(core_PHPSerialize),
767
768
  "PLISTViewer": _wrap(core_PLISTViewer),
768
769
  "padLines": _wrap(core_PadLines),
770
+ "parityBit": _wrap(core_ParityBit),
769
771
  "parseASN1HexString": _wrap(core_ParseASN1HexString),
770
772
  "parseCSR": _wrap(core_ParseCSR),
771
773
  "parseColourCode": _wrap(core_ParseColourCode),
@@ -1260,6 +1262,7 @@ const PHPDeserialize = chef.PHPDeserialize;
1260
1262
  const PHPSerialize = chef.PHPSerialize;
1261
1263
  const PLISTViewer = chef.PLISTViewer;
1262
1264
  const padLines = chef.padLines;
1265
+ const parityBit = chef.parityBit;
1263
1266
  const parseASN1HexString = chef.parseASN1HexString;
1264
1267
  const parseCSR = chef.parseCSR;
1265
1268
  const parseColourCode = chef.parseColourCode;
@@ -1739,6 +1742,7 @@ const operations = [
1739
1742
  PHPSerialize,
1740
1743
  PLISTViewer,
1741
1744
  padLines,
1745
+ parityBit,
1742
1746
  parseASN1HexString,
1743
1747
  parseCSR,
1744
1748
  parseColourCode,
@@ -2222,6 +2226,7 @@ export {
2222
2226
  PHPSerialize,
2223
2227
  PLISTViewer,
2224
2228
  padLines,
2229
+ parityBit,
2225
2230
  parseASN1HexString,
2226
2231
  parseCSR,
2227
2232
  parseColourCode,
@@ -43,17 +43,23 @@ class HTMLOperation {
43
43
  /**
44
44
  * Renders the operation in HTML as a stub operation with no ingredients.
45
45
  *
46
+ * @param {boolean} removeIcon - show icon for removing operation
47
+ * @param {string} elementId - element ID for aria usage
46
48
  * @returns {string}
47
49
  */
48
- toStubHtml(removeIcon) {
50
+ toStubHtml(removeIcon = false, elementId = null) {
49
51
  let html = "<li class='operation'";
50
52
 
53
+ if (elementId) {
54
+ html += ` id='${elementId}'`;
55
+ }
56
+
51
57
  if (this.description) {
52
58
  const infoLink = this.infoURL ? `<hr>${titleFromWikiLink(this.infoURL)}` : "";
53
59
 
54
60
  html += ` data-container='body' data-toggle='popover' data-placement='right'
55
61
  data-content="${this.description}${infoLink}" data-html='true' data-trigger='hover'
56
- data-boundary='viewport'`;
62
+ data-boundary='viewport' role='button'`;
57
63
  }
58
64
 
59
65
  html += ">" + this.name;
@@ -173,7 +173,7 @@
173
173
  Operations
174
174
  <span class="op-count"></span>
175
175
  </div>
176
- <input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off" tabindex="0" data-help-title="Searching for operations" data-help="<p>Use the search box to find useful operations.</p><p>Both operation names and descriptions are queried using a fuzzy matching algorithm.</p>">
176
+ <input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off" tabindex="0" data-help-title="Searching for operations" data-help="<p>Use the search box to find useful operations.</p><p>Both operation names and descriptions are queried using a fuzzy matching algorithm.</p>" aria-owns="search-results">
177
177
  <ul id="search-results" class="op-list"></ul>
178
178
  <div id="categories" class="panel-group no-select"></div>
179
179
  </div>
@@ -28,17 +28,16 @@ class OperationsWaiter {
28
28
  this.removeIntent = false;
29
29
  }
30
30
 
31
-
32
31
  /**
33
32
  * Handler for search events.
34
33
  * Finds operations which match the given search term and displays them under the search box.
35
34
  *
36
- * @param {event} e
35
+ * @param {KeyboardEvent | ClipboardEvent | Event} e
37
36
  */
38
37
  searchOperations(e) {
39
38
  let ops, selected;
40
39
 
41
- if (e.type === "search" || e.keyCode === 13) { // Search or Return
40
+ if ((e.type === "search" && e.target.value !== "") || e.keyCode === 13) { // Search (non-empty) or Return
42
41
  e.preventDefault();
43
42
  ops = document.querySelectorAll("#search-results li");
44
43
  if (ops.length) {
@@ -49,27 +48,43 @@ class OperationsWaiter {
49
48
  }
50
49
  }
51
50
 
51
+ /**
52
+ * Sets up the operation element with the correct attributes when selected
53
+ * @param {HTMLElement} element
54
+ */
55
+ const _selectOperation = (element) => {
56
+ element.classList.add("selected-op");
57
+ element.scrollIntoView({block: "nearest"});
58
+ $(element).popover("show");
59
+ e.target.setAttribute("aria-activedescendant", element.id);
60
+ };
61
+
62
+ /**
63
+ * Sets up the operation element with the correct attributes when deselected
64
+ * @param {HTMLElement} element
65
+ */
66
+ const _deselectOperation = (element) => {
67
+ element.classList.remove("selected-op");
68
+ $(element).popover("hide");
69
+ };
70
+
52
71
  if (e.keyCode === 40) { // Down
53
72
  e.preventDefault();
54
73
  ops = document.querySelectorAll("#search-results li");
55
74
  if (ops.length) {
56
75
  selected = this.getSelectedOp(ops);
57
- if (selected > -1) {
58
- ops[selected].classList.remove("selected-op");
59
- }
76
+ if (selected > -1) _deselectOperation(ops[selected]);
60
77
  if (selected === ops.length-1) selected = -1;
61
- ops[selected+1].classList.add("selected-op");
78
+ _selectOperation(ops[selected+1]);
62
79
  }
63
80
  } else if (e.keyCode === 38) { // Up
64
81
  e.preventDefault();
65
82
  ops = document.querySelectorAll("#search-results li");
66
83
  if (ops.length) {
67
84
  selected = this.getSelectedOp(ops);
68
- if (selected > -1) {
69
- ops[selected].classList.remove("selected-op");
70
- }
85
+ if (selected > -1) _deselectOperation(ops[selected]);
71
86
  if (selected === 0) selected = ops.length;
72
- ops[selected-1].classList.add("selected-op");
87
+ _selectOperation(ops[selected-1]);
73
88
  }
74
89
  } else {
75
90
  const searchResultsEl = document.getElementById("search-results");
@@ -83,11 +98,13 @@ class OperationsWaiter {
83
98
  searchResultsEl.removeChild(searchResultsEl.firstChild);
84
99
  }
85
100
 
101
+ document.querySelector("#search").removeAttribute("aria-activedescendant");
102
+
86
103
  $("#categories .show").collapse("hide");
87
104
  if (str) {
88
105
  const matchedOps = this.filterOperations(str, true);
89
106
  const matchedOpsHtml = matchedOps
90
- .map(v => v.toStubHtml())
107
+ .map((operation, idx) => operation.toStubHtml(false, `search-result-${idx}`))
91
108
  .join("");
92
109
 
93
110
  searchResultsEl.innerHTML = matchedOpsHtml;
@@ -103,7 +120,7 @@ class OperationsWaiter {
103
120
  * @param {string} searchStr
104
121
  * @param {boolean} highlight - Whether or not to highlight the matching string in the operation
105
122
  * name and description
106
- * @returns {string[]}
123
+ * @returns {HTMLOperation[]}
107
124
  */
108
125
  filterOperations(inStr, highlight) {
109
126
  const matchedOps = [];
@@ -589,8 +589,7 @@ Password: 282760`;
589
589
  ...[1, 3, 4, 5, 6, 7].map(version => it(`Analyze UUID v${version}`, () => {
590
590
  const uuid = chef.generateUUID("", { "version": `v${version}` }).toString();
591
591
  const result = chef.analyseUUID(uuid).toString();
592
- const expected = `UUID version: ${version}`;
593
- assert.strictEqual(result, expected);
592
+ assert.ok(result.startsWith(`Version:\n${version}\n`), `Expected output to start with "Version:\\n${version}\\n", got: ${result}`);
594
593
  })),
595
594
 
596
595
  it("Generate UUID using defaults", () => {
@@ -598,7 +597,7 @@ Password: 282760`;
598
597
  assert.ok(uuid);
599
598
 
600
599
  const analysis = chef.analyseUUID(uuid).toString();
601
- assert.strictEqual(analysis, "UUID version: 4");
600
+ assert.ok(analysis.startsWith("Version:\n4\n"), `Expected output to start with "Version:\\n4\\n", got: ${analysis}`);
602
601
  }),
603
602
 
604
603
  it("Gzip, Gunzip", () => {
@@ -16,6 +16,7 @@ import { setLongTestFailure, logTestReport } from "../lib/utils.mjs";
16
16
  import TestRegister from "../lib/TestRegister.mjs";
17
17
  import "./tests/A1Z26CipherDecode.mjs";
18
18
  import "./tests/AESKeyWrap.mjs";
19
+ import "./tests/AnalyseUUID.mjs";
19
20
  import "./tests/AlternatingCaps.mjs";
20
21
  import "./tests/AvroToJSON.mjs";
21
22
  import "./tests/BaconCipher.mjs";
@@ -71,6 +72,7 @@ import "./tests/ExtractAudioMetadata.mjs";
71
72
  import "./tests/ExtractEmailAddresses.mjs";
72
73
  import "./tests/ExtractHashes.mjs";
73
74
  import "./tests/ExtractIPAddresses.mjs";
75
+ import "./tests/Fernet.mjs";
74
76
  import "./tests/Float.mjs";
75
77
  import "./tests/FileTree.mjs";
76
78
  import "./tests/FletcherChecksum.mjs";
@@ -134,6 +136,7 @@ import "./tests/ParseUDP.mjs";
134
136
  import "./tests/PEMtoHex.mjs";
135
137
  import "./tests/PGP.mjs";
136
138
  import "./tests/PHP.mjs";
139
+ import "./tests/ParityBit.mjs";
137
140
  import "./tests/PHPSerialize.mjs";
138
141
  import "./tests/PowerSet.mjs";
139
142
  import "./tests/Protobuf.mjs";
@@ -143,6 +146,8 @@ import "./tests/Rabbit.mjs";
143
146
  import "./tests/RAKE.mjs";
144
147
  import "./tests/Regex.mjs";
145
148
  import "./tests/Register.mjs";
149
+ import "./tests/RegularExpression.mjs";
150
+ import "./tests/RenderMarkdown.mjs";
146
151
  import "./tests/RisonEncodeDecode.mjs";
147
152
  import "./tests/Rotate.mjs";
148
153
  import "./tests/RSA.mjs";
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Analyse UUID tests
3
+ *
4
+ * @author ko80240 [csk.dev@proton.me]
5
+ * @copyright Crown Copyright 2023
6
+ * @license Apache-2.0
7
+ */
8
+ import TestRegister from "../../lib/TestRegister.mjs";
9
+
10
+ TestRegister.addTests([
11
+ {
12
+ "name": "Analyse UUID: v1 UUID extracts timestamp, clock, and node",
13
+ "input": "cefa1760-28ee-11f1-9f95-1fb76af3e239",
14
+ "expectedOutput": "Version:\n1\n\nTimestamp:\n1774514156502\n\nTimestamp (ISO):\n2026-03-26T08:35:56.502Z\n\nNode:\n1F:B7:6A:F3:E2:39\n\nClock:\n8085\n\nUUID Integer:\n275119515460318071558429785403790975545",
15
+ "recipeConfig": [
16
+ {
17
+ "op": "Analyse UUID",
18
+ "args": [true]
19
+ }
20
+ ]
21
+ },
22
+ {
23
+ "name": "Analyse UUID: v7 UUID extracts timestamp, randA, and randB",
24
+ "input": "019d294a-af64-7728-9524-26da08f50708",
25
+ "expectedOutput": "Version:\n7\n\nTimestamp:\n1774514253668\n\nTimestamp (ISO):\n2026-03-26T08:37:33.668Z\n\nRand A:\n1832\n\nRand B:\n952426DA08F50708\n\nUUID Integer:\n2145256098533991595556290452700595976",
26
+ "recipeConfig": [
27
+ {
28
+ "op": "Analyse UUID",
29
+ "args": [true]
30
+ }
31
+ ]
32
+ },
33
+ {
34
+ "name": "Analyse UUID: v4 UUID should show no metadata - not possible",
35
+ "input": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
36
+ "expectedOutput": "Version:\n4\n\nNo metadata available. Only versions 1, 6, 7 are supported.\n\nUUID Integer:\n324969006592305634633390616021200786553",
37
+ "recipeConfig": [
38
+ {
39
+ "op": "Analyse UUID",
40
+ "args": [true]
41
+ }
42
+ ]
43
+ },
44
+ {
45
+ "name": "Analyse UUID: if the 'Include Metadata' option is false it should return not metadata",
46
+ "input": "cefa1760-28ee-11f1-9f95-1fb76af3e239",
47
+ "expectedOutput": "Version:\n1\n\nUUID Integer:\n275119515460318071558429785403790975545",
48
+ "recipeConfig": [
49
+ {
50
+ "op": "Analyse UUID",
51
+ "args": [false]
52
+ }
53
+ ]
54
+ },
55
+ {
56
+ "name": "Analyse UUID: invalid UUID should return error message",
57
+ "input": "not-a-uuid",
58
+ "expectedOutput": "Invalid UUID",
59
+ "recipeConfig": [
60
+ {
61
+ "op": "Analyse UUID",
62
+ "args": [true]
63
+ }
64
+ ]
65
+ }
66
+ ]);
@@ -11,44 +11,70 @@ TestRegister.addTests([
11
11
  {
12
12
  name: "Extract email address",
13
13
  input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
14
- expectedOutput: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com",
14
+ expectedOutput:
15
+ "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com",
15
16
  recipeConfig: [
16
17
  {
17
- "op": "Extract email addresses",
18
- "args": [false]
18
+ op: "Extract email addresses",
19
+ args: [false],
19
20
  },
20
21
  ],
21
22
  },
22
23
  {
23
24
  name: "Extract email address - Display total",
24
25
  input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
25
- expectedOutput: "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com",
26
+ expectedOutput:
27
+ "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com",
26
28
  recipeConfig: [
27
29
  {
28
- "op": "Extract email addresses",
29
- "args": [true]
30
+ op: "Extract email addresses",
31
+ args: [true],
30
32
  },
31
33
  ],
32
34
  },
33
35
  {
34
36
  name: "Extract email address (Internationalized)",
35
37
  input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
36
- expectedOutput: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
38
+ expectedOutput:
39
+ "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
37
40
  recipeConfig: [
38
41
  {
39
- "op": "Extract email addresses",
40
- "args": [false]
42
+ op: "Extract email addresses",
43
+ args: [false],
41
44
  },
42
45
  ],
43
46
  },
44
47
  {
45
48
  name: "Extract email address - Display total (Internationalized)",
46
49
  input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
47
- expectedOutput: "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
50
+ expectedOutput:
51
+ "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
48
52
  recipeConfig: [
49
53
  {
50
- "op": "Extract email addresses",
51
- "args": [true]
54
+ op: "Extract email addresses",
55
+ args: [true],
56
+ },
57
+ ],
58
+ },
59
+ {
60
+ name: "Extract email address - IP address",
61
+ input: "yaunwfkb\nexample@[127.0.0.1]\n091nvka",
62
+ expectedOutput: "example@[127.0.0.1]",
63
+ recipeConfig: [
64
+ {
65
+ op: "Extract email addresses",
66
+ args: [false],
67
+ },
68
+ ],
69
+ },
70
+ {
71
+ name: "Extract email address - invalid IP address",
72
+ input: "yaunwfkb\nfalse_positive@[1.2.3.]\n091nvka",
73
+ expectedOutput: "",
74
+ recipeConfig: [
75
+ {
76
+ op: "Extract email addresses",
77
+ args: [false],
52
78
  },
53
79
  ],
54
80
  },
@@ -5,7 +5,7 @@
5
5
  * @copyright Karsten Silkenbäumer 2019
6
6
  * @license Apache-2.0
7
7
  */
8
- import TestRegister from "../TestRegister";
8
+ import TestRegister from "../../lib/TestRegister.mjs";
9
9
 
10
10
  TestRegister.addTests([
11
11
  {
@@ -47,7 +47,7 @@ TestRegister.addTests([
47
47
  {
48
48
  name: "Fernet Encrypt: no input",
49
49
  input: "",
50
- expectedMatch: /^gAAAAABce-[\w-]+={0,2}$/,
50
+ expectedMatch: /^gAAA[\w-]+={0,2}$/,
51
51
  recipeConfig: [
52
52
  {
53
53
  op: "Fernet Encrypt",
@@ -69,12 +69,27 @@ TestRegister.addTests([
69
69
  {
70
70
  name: "Fernet Encrypt: valid arguments",
71
71
  input: "This is a secret message.\n",
72
- expectedMatch: /^gAAAAABce-[\w-]+={0,2}$/,
72
+ expectedMatch: /^gAAA[\w-]+={0,2}$/,
73
73
  recipeConfig: [
74
74
  {
75
75
  op: "Fernet Encrypt",
76
76
  args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
77
77
  }
78
78
  ],
79
+ },
80
+ {
81
+ name: "Fernet Encrypt/Decrypt: round trip",
82
+ input: "This is a secret message.\n",
83
+ expectedOutput: "This is a secret message.\n",
84
+ recipeConfig: [
85
+ {
86
+ op: "Fernet Encrypt",
87
+ args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
88
+ },
89
+ {
90
+ op: "Fernet Decrypt",
91
+ args: ["MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="]
92
+ },
93
+ ],
79
94
  }
80
95
  ]);