cyberchef 9.38.5 → 9.38.8

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyberchef",
3
- "version": "9.38.5",
3
+ "version": "9.38.8",
4
4
  "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
5
5
  "author": "n1474335 <n1474335@gmail.com>",
6
6
  "homepage": "https://gchq.github.io/CyberChef",
@@ -122,6 +122,7 @@
122
122
  "js-crc": "^0.2.0",
123
123
  "js-sha3": "^0.8.0",
124
124
  "jsesc": "^3.0.2",
125
+ "json5": "^2.2.1",
125
126
  "jsonpath": "^1.1.1",
126
127
  "jsonwebtoken": "^8.5.1",
127
128
  "jsqr": "^1.4.0",
@@ -7637,10 +7637,10 @@
7637
7637
  },
7638
7638
  "JSON Beautify": {
7639
7639
  "module": "Code",
7640
- "description": "Indents and prettifies JavaScript Object Notation (JSON) code.",
7640
+ "description": "Indents and pretty prints JavaScript Object Notation (JSON) code.<br><br>Tags: json viewer, prettify, syntax highlighting",
7641
7641
  "infoURL": null,
7642
7642
  "inputType": "string",
7643
- "outputType": "string",
7643
+ "outputType": "html",
7644
7644
  "flowControl": false,
7645
7645
  "manualBake": false,
7646
7646
  "args": [
@@ -7653,6 +7653,11 @@
7653
7653
  "name": "Sort Object Keys",
7654
7654
  "type": "boolean",
7655
7655
  "value": false
7656
+ },
7657
+ {
7658
+ "name": "Formatted",
7659
+ "type": "boolean",
7660
+ "value": true
7656
7661
  }
7657
7662
  ]
7658
7663
  },
@@ -8578,14 +8583,20 @@
8578
8583
  ]
8579
8584
  },
8580
8585
  "PEM to Hex": {
8581
- "module": "PublicKey",
8586
+ "module": "Default",
8582
8587
  "description": "Converts PEM (Privacy Enhanced Mail) format to a hexadecimal DER (Distinguished Encoding Rules) string.",
8583
- "infoURL": "https://wikipedia.org/wiki/X.690#DER_encoding",
8588
+ "infoURL": "https://wikipedia.org/wiki/Privacy-Enhanced_Mail#Format",
8584
8589
  "inputType": "string",
8585
8590
  "outputType": "string",
8586
8591
  "flowControl": false,
8587
8592
  "manualBake": false,
8588
- "args": []
8593
+ "args": [],
8594
+ "checks": [
8595
+ {
8596
+ "pattern": "----BEGIN ([A-Z][A-Z ]+[A-Z])-----",
8597
+ "args": []
8598
+ }
8599
+ ]
8589
8600
  },
8590
8601
  "PGP Decrypt": {
8591
8602
  "module": "PGP",
@@ -89,6 +89,7 @@ import NOT from "../../operations/NOT.mjs";
89
89
  import Numberwang from "../../operations/Numberwang.mjs";
90
90
  import OR from "../../operations/OR.mjs";
91
91
  import OffsetChecker from "../../operations/OffsetChecker.mjs";
92
+ import PEMToHex from "../../operations/PEMToHex.mjs";
92
93
  import PHPDeserialize from "../../operations/PHPDeserialize.mjs";
93
94
  import PadLines from "../../operations/PadLines.mjs";
94
95
  import ParseColourCode from "../../operations/ParseColourCode.mjs";
@@ -256,6 +257,7 @@ OpModules.Default = {
256
257
  "Numberwang": Numberwang,
257
258
  "OR": OR,
258
259
  "Offset checker": OffsetChecker,
260
+ "PEM to Hex": PEMToHex,
259
261
  "PHP Deserialize": PHPDeserialize,
260
262
  "Pad lines": PadLines,
261
263
  "Parse colour code": ParseColourCode,
@@ -8,7 +8,6 @@
8
8
  import HexToObjectIdentifier from "../../operations/HexToObjectIdentifier.mjs";
9
9
  import HexToPEM from "../../operations/HexToPEM.mjs";
10
10
  import ObjectIdentifierToHex from "../../operations/ObjectIdentifierToHex.mjs";
11
- import PEMToHex from "../../operations/PEMToHex.mjs";
12
11
  import ParseASN1HexString from "../../operations/ParseASN1HexString.mjs";
13
12
  import ParseX509Certificate from "../../operations/ParseX509Certificate.mjs";
14
13
 
@@ -18,7 +17,6 @@ OpModules.PublicKey = {
18
17
  "Hex to Object Identifier": HexToObjectIdentifier,
19
18
  "Hex to PEM": HexToPEM,
20
19
  "Object Identifier to Hex": ObjectIdentifierToHex,
21
- "PEM to Hex": PEMToHex,
22
20
  "Parse ASN.1 hex string": ParseASN1HexString,
23
21
  "Parse X.509 certificate": ParseX509Certificate,
24
22
  };
@@ -130,10 +130,11 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
130
130
  i = 0;
131
131
 
132
132
  while (i < data.length) {
133
- enc1 = alphabet.indexOf(data.charAt(i++));
134
- enc2 = alphabet.indexOf(data.charAt(i++));
135
- enc3 = alphabet.indexOf(data.charAt(i++));
136
- enc4 = alphabet.indexOf(data.charAt(i++));
133
+ // Including `|| null` forces empty strings to null so that indexOf returns -1 instead of 0
134
+ enc1 = alphabet.indexOf(data.charAt(i++) || null);
135
+ enc2 = alphabet.indexOf(data.charAt(i++) || null);
136
+ enc3 = alphabet.indexOf(data.charAt(i++) || null);
137
+ enc4 = alphabet.indexOf(data.charAt(i++) || null);
137
138
 
138
139
  if (strictMode && (enc1 < 0 || enc2 < 0 || enc3 < 0 || enc4 < 0)) {
139
140
  throw new OperationError("Error: Base64 input contains non-alphabet char(s)");
@@ -143,13 +144,13 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
143
144
  chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
144
145
  chr3 = ((enc3 & 3) << 6) | enc4;
145
146
 
146
- if (chr1 < 256) {
147
+ if (chr1 >= 0 && chr1 < 256) {
147
148
  output.push(chr1);
148
149
  }
149
- if (chr2 < 256 && enc3 !== 64) {
150
+ if (chr2 >= 0 && chr2 < 256 && enc3 !== 64) {
150
151
  output.push(chr2);
151
152
  }
152
- if (chr3 < 256 && enc4 !== 64) {
153
+ if (chr3 >= 0 && chr3 < 256 && enc4 !== 64) {
153
154
  output.push(chr3);
154
155
  }
155
156
  }
@@ -5,8 +5,10 @@
5
5
  * @license Apache-2.0
6
6
  */
7
7
 
8
- import vkbeautify from "vkbeautify";
8
+ import JSON5 from "json5";
9
+ import OperationError from "../errors/OperationError.mjs";
9
10
  import Operation from "../Operation.mjs";
11
+ import Utils from "../Utils.mjs";
10
12
 
11
13
  /**
12
14
  * JSON Beautify operation
@@ -21,19 +23,25 @@ class JSONBeautify extends Operation {
21
23
 
22
24
  this.name = "JSON Beautify";
23
25
  this.module = "Code";
24
- this.description = "Indents and prettifies JavaScript Object Notation (JSON) code.";
26
+ this.description = "Indents and pretty prints JavaScript Object Notation (JSON) code.<br><br>Tags: json viewer, prettify, syntax highlighting";
25
27
  this.inputType = "string";
26
28
  this.outputType = "string";
29
+ this.presentType = "html";
27
30
  this.args = [
28
31
  {
29
- "name": "Indent string",
30
- "type": "binaryShortString",
31
- "value": " "
32
+ name: "Indent string",
33
+ type: "binaryShortString",
34
+ value: " "
32
35
  },
33
36
  {
34
- "name": "Sort Object Keys",
35
- "type": "boolean",
36
- "value": false
37
+ name: "Sort Object Keys",
38
+ type: "boolean",
39
+ value: false
40
+ },
41
+ {
42
+ name: "Formatted",
43
+ type: "boolean",
44
+ value: true
37
45
  }
38
46
  ];
39
47
  }
@@ -44,35 +52,193 @@ class JSONBeautify extends Operation {
44
52
  * @returns {string}
45
53
  */
46
54
  run(input, args) {
55
+ if (!input) return "";
56
+
47
57
  const [indentStr, sortBool] = args;
58
+ let json = null;
48
59
 
49
- if (!input) return "";
50
- if (sortBool) {
51
- input = JSON.stringify(JSONBeautify._sort(JSON.parse(input)));
60
+ try {
61
+ json = JSON5.parse(input);
62
+ } catch (err) {
63
+ throw new OperationError("Unable to parse input as JSON.\n" + err);
52
64
  }
53
- return vkbeautify.json(input, indentStr);
54
- }
55
65
 
66
+ if (sortBool) json = sortKeys(json);
67
+
68
+ return JSON.stringify(json, null, indentStr);
69
+ }
56
70
 
57
71
  /**
58
- * Sort JSON representation of an object
72
+ * Adds various dynamic features to the JSON blob
59
73
  *
60
- * @author Phillip Nordwall [phillip.nordwall@gmail.com]
61
- * @private
62
- * @param {object} o
63
- * @returns {object}
74
+ * @param {string} data
75
+ * @param {Object[]} args
76
+ * @returns {html}
64
77
  */
65
- static _sort(o) {
66
- if (Array.isArray(o)) {
67
- return o.map(JSONBeautify._sort);
68
- } else if ("[object Object]" === Object.prototype.toString.call(o)) {
69
- return Object.keys(o).sort().reduce(function(a, k) {
70
- a[k] = JSONBeautify._sort(o[k]);
71
- return a;
72
- }, {});
78
+ present(data, args) {
79
+ const formatted = args[2];
80
+ if (!formatted) return Utils.escapeHtml(data);
81
+
82
+ const json = JSON5.parse(data);
83
+ const options = {
84
+ withLinks: true,
85
+ bigNumbers: true
86
+ };
87
+ let html = '<div class="json-document">';
88
+
89
+ if (isCollapsable(json)) {
90
+ const isArr = json instanceof Array;
91
+ html += '<details open class="json-details">' +
92
+ `<summary class="json-summary ${isArr ? "json-arr" : "json-obj"}"></summary>` +
93
+ json2html(json, options) +
94
+ "</details>";
95
+ } else {
96
+ html += json2html(json, options);
97
+ }
98
+
99
+ html += "</div>";
100
+ return html;
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Sort keys in a JSON object
106
+ *
107
+ * @author Phillip Nordwall [phillip.nordwall@gmail.com]
108
+ * @param {object} o
109
+ * @returns {object}
110
+ */
111
+ function sortKeys(o) {
112
+ if (Array.isArray(o)) {
113
+ return o.map(sortKeys);
114
+ } else if ("[object Object]" === Object.prototype.toString.call(o)) {
115
+ return Object.keys(o).sort().reduce(function(a, k) {
116
+ a[k] = sortKeys(o[k]);
117
+ return a;
118
+ }, {});
119
+ }
120
+ return o;
121
+ }
122
+
123
+
124
+ /**
125
+ * Check if arg is either an array with at least 1 element, or a dict with at least 1 key
126
+ * @returns {boolean}
127
+ */
128
+ function isCollapsable(arg) {
129
+ return arg instanceof Object && Object.keys(arg).length > 0;
130
+ }
131
+
132
+ /**
133
+ * Check if a string looks like a URL, based on protocol
134
+ * @returns {boolean}
135
+ */
136
+ function isUrl(string) {
137
+ const protocols = ["http", "https", "ftp", "ftps"];
138
+ for (let i = 0; i < protocols.length; i++) {
139
+ if (string.startsWith(protocols[i] + "://")) {
140
+ return true;
141
+ }
142
+ }
143
+ return false;
144
+ }
145
+
146
+ /**
147
+ * Transform a json object into html representation
148
+ *
149
+ * Adapted for CyberChef by @n1474335 from jQuery json-viewer
150
+ * @author Alexandre Bodelot <alexandre.bodelot@gmail.com>
151
+ * @link https://github.com/abodelot/jquery.json-viewer
152
+ * @license MIT
153
+ *
154
+ * @returns {string}
155
+ */
156
+ function json2html(json, options) {
157
+ let html = "";
158
+ if (typeof json === "string") {
159
+ // Escape tags and quotes
160
+ json = Utils.escapeHtml(json);
161
+
162
+ if (options.withLinks && isUrl(json)) {
163
+ html += `<a href="${json}" class="json-string" target="_blank">${json}</a>`;
164
+ } else {
165
+ // Escape double quotes in the rendered non-URL string.
166
+ json = json.replace(/&quot;/g, "\\&quot;");
167
+ html += `<span class="json-string">"${json}"</span>`;
168
+ }
169
+ } else if (typeof json === "number" || typeof json === "bigint") {
170
+ html += `<span class="json-literal">${json}</span>`;
171
+ } else if (typeof json === "boolean") {
172
+ html += `<span class="json-literal">${json}</span>`;
173
+ } else if (json === null) {
174
+ html += '<span class="json-literal">null</span>';
175
+ } else if (json instanceof Array) {
176
+ if (json.length > 0) {
177
+ html += '<span class="json-bracket">[</span><ol class="json-array">';
178
+ for (let i = 0; i < json.length; i++) {
179
+ html += "<li>";
180
+
181
+ // Add toggle button if item is collapsable
182
+ if (isCollapsable(json[i])) {
183
+ const isArr = json[i] instanceof Array;
184
+ html += '<details open class="json-details">' +
185
+ `<summary class="json-summary ${isArr ? "json-arr" : "json-obj"}"></summary>` +
186
+ json2html(json[i], options) +
187
+ "</details>";
188
+ } else {
189
+ html += json2html(json[i], options);
190
+ }
191
+
192
+ // Add comma if item is not last
193
+ if (i < json.length - 1) {
194
+ html += '<span class="json-comma">,</span>';
195
+ }
196
+ html += "</li>";
197
+ }
198
+ html += '</ol><span class="json-bracket">]</span>';
199
+ } else {
200
+ html += '<span class="json-bracket">[]</span>';
201
+ }
202
+ } else if (typeof json === "object") {
203
+ // Optional support different libraries for big numbers
204
+ // json.isLosslessNumber: package lossless-json
205
+ // json.toExponential(): packages bignumber.js, big.js, decimal.js, decimal.js-light, others?
206
+ if (options.bigNumbers && (typeof json.toExponential === "function" || json.isLosslessNumber)) {
207
+ html += `<span class="json-literal">${json.toString()}</span>`;
208
+ } else {
209
+ let keyCount = Object.keys(json).length;
210
+ if (keyCount > 0) {
211
+ html += '<span class="json-brace">{</span><ul class="json-dict">';
212
+ for (const key in json) {
213
+ if (Object.prototype.hasOwnProperty.call(json, key)) {
214
+ const safeKey = Utils.escapeHtml(key);
215
+ html += "<li>";
216
+
217
+ // Add toggle button if item is collapsable
218
+ if (isCollapsable(json[key])) {
219
+ const isArr = json[key] instanceof Array;
220
+ html += '<details open class="json-details">' +
221
+ `<summary class="json-summary ${isArr ? "json-arr" : "json-obj"}">${safeKey}<span class="json-colon">:</span> </summary>` +
222
+ json2html(json[key], options) +
223
+ "</details>";
224
+ } else {
225
+ html += safeKey + '<span class="json-colon">:</span> ' + json2html(json[key], options);
226
+ }
227
+
228
+ // Add comma if item is not last
229
+ if (--keyCount > 0) {
230
+ html += '<span class="json-comma">,</span>';
231
+ }
232
+ html += "</li>";
233
+ }
234
+ }
235
+ html += '</ul><span class="json-brace">}</span>';
236
+ } else {
237
+ html += '<span class="json-brace">{}</span>';
238
+ }
73
239
  }
74
- return o;
75
240
  }
241
+ return html;
76
242
  }
77
243
 
78
244
  export default JSONBeautify;
@@ -1,11 +1,14 @@
1
1
  /**
2
2
  * @author n1474335 [n1474335@gmail.com]
3
+ * @author cplussharp
3
4
  * @copyright Crown Copyright 2016
4
5
  * @license Apache-2.0
5
6
  */
6
7
 
7
- import r from "jsrsasign";
8
+ import { fromBase64 } from "../lib/Base64.mjs";
9
+ import { toHexFast } from "../lib/Hex.mjs";
8
10
  import Operation from "../Operation.mjs";
11
+ import OperationError from "../errors/OperationError.mjs";
9
12
 
10
13
  /**
11
14
  * PEM to Hex operation
@@ -19,12 +22,18 @@ class PEMToHex extends Operation {
19
22
  super();
20
23
 
21
24
  this.name = "PEM to Hex";
22
- this.module = "PublicKey";
25
+ this.module = "Default";
23
26
  this.description = "Converts PEM (Privacy Enhanced Mail) format to a hexadecimal DER (Distinguished Encoding Rules) string.";
24
- this.infoURL = "https://wikipedia.org/wiki/X.690#DER_encoding";
27
+ this.infoURL = "https://wikipedia.org/wiki/Privacy-Enhanced_Mail#Format";
25
28
  this.inputType = "string";
26
29
  this.outputType = "string";
27
30
  this.args = [];
31
+ this.checks = [
32
+ {
33
+ "pattern": "----BEGIN ([A-Z][A-Z ]+[A-Z])-----",
34
+ "args": []
35
+ }
36
+ ];
28
37
  }
29
38
 
30
39
  /**
@@ -33,17 +42,25 @@ class PEMToHex extends Operation {
33
42
  * @returns {string}
34
43
  */
35
44
  run(input, args) {
36
- if (input.indexOf("-----BEGIN") < 0) {
37
- // Add header so that the KEYUTIL function works
38
- input = "-----BEGIN CERTIFICATE-----" + input;
39
- }
40
- if (input.indexOf("-----END") < 0) {
41
- // Add footer so that the KEYUTIL function works
42
- input = input + "-----END CERTIFICATE-----";
45
+ const output = [];
46
+ let match;
47
+ const regex = /-----BEGIN ([A-Z][A-Z ]+[A-Z])-----/g;
48
+ while ((match = regex.exec(input)) !== null) {
49
+ // find corresponding end tag
50
+ const indexBase64 = match.index + match[0].length;
51
+ const footer = `-----END ${match[1]}-----`;
52
+ const indexFooter = input.indexOf(footer, indexBase64);
53
+ if (indexFooter === -1) {
54
+ throw new OperationError(`PEM footer '${footer}' not found`);
55
+ }
56
+
57
+ // decode base64 content
58
+ const base64 = input.substring(indexBase64, indexFooter);
59
+ const bytes = fromBase64(base64, "A-Za-z0-9+/=", "byteArray", true);
60
+ const hex = toHexFast(bytes);
61
+ output.push(hex);
43
62
  }
44
- const cert = new r.X509();
45
- cert.readCertPEM(input);
46
- return cert.hex;
63
+ return output.join("\n");
47
64
  }
48
65
 
49
66
  }
@@ -34,3 +34,6 @@
34
34
  @import "./layout/_operations.css";
35
35
  @import "./layout/_recipe.css";
36
36
  @import "./layout/_structure.css";
37
+
38
+ /* Operations */
39
+ @import "./operations/json.css";
@@ -0,0 +1,78 @@
1
+ /**
2
+ * JSON styles
3
+ *
4
+ * @author n1474335 [n1474335@gmail.com]
5
+ * @copyright Crown Copyright 2022
6
+ * @license Apache-2.0
7
+ *
8
+ * Adapted for CyberChef by @n1474335 from jQuery json-viewer
9
+ * @author Alexandre Bodelot <alexandre.bodelot@gmail.com>
10
+ * @link https://github.com/abodelot/jquery.json-viewer
11
+ * @license MIT
12
+ */
13
+
14
+ /* Root element */
15
+ .json-document {
16
+ padding: .5em 1.5em;
17
+ }
18
+
19
+ /* Syntax highlighting for JSON objects */
20
+ ul.json-dict, ol.json-array {
21
+ list-style-type: none;
22
+ margin: 0 0 0 1px;
23
+ border-left: 1px dotted #ccc;
24
+ padding-left: 2em;
25
+ }
26
+ .json-string {
27
+ color: green;
28
+ }
29
+ .json-literal {
30
+ color: red;
31
+ }
32
+ .json-brace,
33
+ .json-bracket,
34
+ .json-colon,
35
+ .json-comma {
36
+ color: gray;
37
+ }
38
+
39
+ /* Collapse */
40
+ .json-details {
41
+ display: inline;
42
+ }
43
+ .json-details[open] {
44
+ display: contents;
45
+ }
46
+ .json-summary {
47
+ display: contents;
48
+ }
49
+
50
+ /* Display object and array brackets when closed */
51
+ .json-summary.json-obj::after {
52
+ color: gray;
53
+ content: "{ ... }"
54
+ }
55
+ .json-summary.json-arr::after {
56
+ color: gray;
57
+ content: "[ ... ]"
58
+ }
59
+ .json-details[open] > .json-summary.json-obj::after,
60
+ .json-details[open] > .json-summary.json-arr::after {
61
+ content: "";
62
+ }
63
+
64
+ /* Show arrows, even in inline mode */
65
+ .json-summary::before {
66
+ content: "\25BC";
67
+ color: #c0c0c0;
68
+ margin-left: -12px;
69
+ margin-right: 5px;
70
+ display: inline-block;
71
+ transform: rotate(-90deg);
72
+ }
73
+ .json-summary:hover::before {
74
+ color: #aaa;
75
+ }
76
+ .json-details[open] > .json-summary::before {
77
+ transform: rotate(0deg);
78
+ }
@@ -67,6 +67,7 @@ import "./tests/PGP.mjs";
67
67
  import "./tests/PHP.mjs";
68
68
  import "./tests/ParseIPRange.mjs";
69
69
  import "./tests/ParseQRCode.mjs";
70
+ import "./tests/PEMtoHex.mjs";
70
71
  import "./tests/PowerSet.mjs";
71
72
  import "./tests/Regex.mjs";
72
73
  import "./tests/Register.mjs";
@@ -16,7 +16,7 @@ TestRegister.addTests([
16
16
  recipeConfig: [
17
17
  {
18
18
  op: "JSON Beautify",
19
- args: [" ", false],
19
+ args: [" ", false, false],
20
20
  },
21
21
  ],
22
22
  },
@@ -27,7 +27,7 @@ TestRegister.addTests([
27
27
  recipeConfig: [
28
28
  {
29
29
  op: "JSON Beautify",
30
- args: [" ", false],
30
+ args: [" ", false, false],
31
31
  },
32
32
  ],
33
33
  },
@@ -38,8 +38,12 @@ TestRegister.addTests([
38
38
  recipeConfig: [
39
39
  {
40
40
  op: "JSON Beautify",
41
- args: [" ", false],
41
+ args: [" ", false, false],
42
42
  },
43
+ {
44
+ op: "HTML To Text",
45
+ args: []
46
+ }
43
47
  ],
44
48
  },
45
49
  {
@@ -49,7 +53,7 @@ TestRegister.addTests([
49
53
  recipeConfig: [
50
54
  {
51
55
  op: "JSON Beautify",
52
- args: [" ", false],
56
+ args: [" ", false, false],
53
57
  },
54
58
  ],
55
59
  },
@@ -60,7 +64,7 @@ TestRegister.addTests([
60
64
  recipeConfig: [
61
65
  {
62
66
  op: "JSON Beautify",
63
- args: [" ", false],
67
+ args: [" ", false, false],
64
68
  },
65
69
  ],
66
70
  },
@@ -71,7 +75,7 @@ TestRegister.addTests([
71
75
  recipeConfig: [
72
76
  {
73
77
  op: "JSON Beautify",
74
- args: [" ", false],
78
+ args: [" ", false, false],
75
79
  },
76
80
  ],
77
81
  },
@@ -82,7 +86,7 @@ TestRegister.addTests([
82
86
  recipeConfig: [
83
87
  {
84
88
  op: "JSON Beautify",
85
- args: ["\t", false],
89
+ args: ["\t", false, false],
86
90
  },
87
91
  ],
88
92
  },
@@ -93,8 +97,12 @@ TestRegister.addTests([
93
97
  recipeConfig: [
94
98
  {
95
99
  op: "JSON Beautify",
96
- args: [" ", false],
100
+ args: [" ", false, false],
97
101
  },
102
+ {
103
+ op: "HTML To Text",
104
+ args: []
105
+ }
98
106
  ],
99
107
  },
100
108
  {
@@ -104,8 +112,12 @@ TestRegister.addTests([
104
112
  recipeConfig: [
105
113
  {
106
114
  op: "JSON Beautify",
107
- args: ["\t", false],
115
+ args: ["\t", false, false],
108
116
  },
117
+ {
118
+ op: "HTML To Text",
119
+ args: []
120
+ }
109
121
  ],
110
122
  },
111
123
  {
@@ -115,8 +127,12 @@ TestRegister.addTests([
115
127
  recipeConfig: [
116
128
  {
117
129
  op: "JSON Beautify",
118
- args: ["\t", true],
130
+ args: ["\t", true, false],
119
131
  },
132
+ {
133
+ op: "HTML To Text",
134
+ args: []
135
+ }
120
136
  ],
121
137
  },
122
138
  ]);
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Test PEMtoHex with different inputs
3
+ *
4
+ * @author cplussharp
5
+ *
6
+ * @license Apache-2.0
7
+ */
8
+
9
+ import TestRegister from "../../lib/TestRegister.mjs";
10
+
11
+ /** RSA 2048bit key pair as PKCS1 and PKCS8 and as certificate */
12
+ const PEMS_RSA_PRIVATE_KEY_PKCS1 = `-----BEGIN RSA PRIVATE KEY-----
13
+ MIIEogIBAAKCAQEA5WykLKHiBAhmZh5WhocgpQQqZjdrApuRxRT21SJZx6Ce+Oz2
14
+ V17/heozu5LEz63jCxW1NrBckzl/Ys8p9LeqYTu6x/LbKloTjfEWxlzXnzUSqn9J
15
+ HIxmmJQzjXp9X1D99Tj+NWpRGEIiCFE7JfDhe2KnMGVDDg6kfCLokDdLo256LeQ4
16
+ CEkViwY6d+at4xDlIHwvZZmG4Smk56eHhvQE3I8sSAzgoLMBamQ5m3MbiULAYtxs
17
+ kCpCfjFxrL6Ziaaj7HZoneF40R30KCI9ygF8vkzxLwe3t5Y4XgHL9TYQm1+BDnin
18
+ upIB/zTeO1ygBGA66m6zpmkmuG7d8HXIducz+wIDAQABAoIBACQu3jWr0lmQeZXh
19
+ cwQEi8F6xrUYSGhA4NyUUdmLcV1ql6fqt29QLDySk1Yh76hRZF17LvlRF0ig6NZM
20
+ lfFihhyPrwWZ57bmPe9E9rKSMe+KD0eUi5NVEVk/BmJpzxwZSfRC6NTDz8Zjp7po
21
+ FUwGkYlEJdocHlc5N/fcCZG1Jti/Z1AsZIjO6r6S0O7neC7icECBKHUyWa8/yE1N
22
+ ++TVyMV+z53Ad1PC+SHMGDlbqJAM3o4wAzD/FAIzyVo6GSnnC+bFdgMtIwtwgYTH
23
+ rbr8M8j5fqAHTqNJeblqt/5KHEj2VVsIsHIuQ6lv4llESEqmH+N5KE4O33U7/Wmj
24
+ y/+VGAECgYEA9ysROHXOx1ofh3tI/r2C2FUan6/AAe4dc+8E4jMGI5T4xeqYHTRV
25
+ l1yS+ZKIxqclIoAmd6SJ7Nx2GdQ55MmokZdZRqsFN1flFOZw2kFH/I0zQZXdOjF+
26
+ sf5Lu0FfcTw3VJhJ/YU3CVdlgdP4ekHbaJVFW5i/pTUf5vNs6AGBGxsCgYEA7Z9D
27
+ 0qnF6GhxA8lJfwnyuktYnwIQoXE6Xp26/NZD7t7HzxHDf43LQxmTk+mDP/yIQHwb
28
+ xIx2NE/ncNxlUMl/g1PkJbKVkB8tdIZrLyiT4lebeqgT72Q07IsxRl/GHOr7CfN0
29
+ 61OBRCe44IlOtaNAZk4zWwuAwAYx+G8ifuOJ+KECgYBP5NvsJChyx+7pHDC8JwXk
30
+ Z53zgBvQg+eBUgGCHHwfhEflsa75wbDo/EOF6JfNnrmiLUpB4i2zIpAKSU9tZMHY
31
+ TdPNw/orqX2jA9n2sqNSP1ISIR8hcF5Dqq9QGBGByLUZ4yAHksf3fQiSrrHi0ubZ
32
+ J2cD9Jv+Cu4E+Sp61AGngQKBgHmuTPTbq1TP5s+hi9laJsnvO3pxfEKv0MwSyWYf
33
+ 8rmnq3oGBq6S1buOpVvhAC0MDFm5NB76Lq2rHUFWGyu7g2ik1PfY823SCVzaWJjV
34
+ lqUZZ6zv1QWJsvBOdvUqpjC4w8TcvsqjAFb+YFXa+ktZRekdsn607UFn6r7laizA
35
+ KC8BAoGAZty7sIGMt1gDaoIjySgOox8x7AlY3QUyNQC5N8KW3MZ8KLC5UBtjhqLy
36
+ wYOJr+/1R/7ibiHrKkIE/dmg5QN1iS5tZmFvyLwJ+nHQZObFrlcKtpr+1lekQY/m
37
+ ly6YJFk3yj2nhYzt8eVXBX2lCoLG1gsrbpXvUfIGJ53L9m1mVAo=
38
+ -----END RSA PRIVATE KEY-----`;
39
+
40
+ const PEMS_RSA_PRIVATE_KEY_PKCS8 = `-----BEGIN PRIVATE KEY-----
41
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDlbKQsoeIECGZm
42
+ HlaGhyClBCpmN2sCm5HFFPbVIlnHoJ747PZXXv+F6jO7ksTPreMLFbU2sFyTOX9i
43
+ zyn0t6phO7rH8tsqWhON8RbGXNefNRKqf0kcjGaYlDONen1fUP31OP41alEYQiII
44
+ UTsl8OF7YqcwZUMODqR8IuiQN0ujbnot5DgISRWLBjp35q3jEOUgfC9lmYbhKaTn
45
+ p4eG9ATcjyxIDOCgswFqZDmbcxuJQsBi3GyQKkJ+MXGsvpmJpqPsdmid4XjRHfQo
46
+ Ij3KAXy+TPEvB7e3ljheAcv1NhCbX4EOeKe6kgH/NN47XKAEYDrqbrOmaSa4bt3w
47
+ dch25zP7AgMBAAECggEAJC7eNavSWZB5leFzBASLwXrGtRhIaEDg3JRR2YtxXWqX
48
+ p+q3b1AsPJKTViHvqFFkXXsu+VEXSKDo1kyV8WKGHI+vBZnntuY970T2spIx74oP
49
+ R5SLk1URWT8GYmnPHBlJ9ELo1MPPxmOnumgVTAaRiUQl2hweVzk399wJkbUm2L9n
50
+ UCxkiM7qvpLQ7ud4LuJwQIEodTJZrz/ITU375NXIxX7PncB3U8L5IcwYOVuokAze
51
+ jjADMP8UAjPJWjoZKecL5sV2Ay0jC3CBhMetuvwzyPl+oAdOo0l5uWq3/kocSPZV
52
+ Wwiwci5DqW/iWURISqYf43koTg7fdTv9aaPL/5UYAQKBgQD3KxE4dc7HWh+He0j+
53
+ vYLYVRqfr8AB7h1z7wTiMwYjlPjF6pgdNFWXXJL5kojGpyUigCZ3pIns3HYZ1Dnk
54
+ yaiRl1lGqwU3V+UU5nDaQUf8jTNBld06MX6x/ku7QV9xPDdUmEn9hTcJV2WB0/h6
55
+ QdtolUVbmL+lNR/m82zoAYEbGwKBgQDtn0PSqcXoaHEDyUl/CfK6S1ifAhChcTpe
56
+ nbr81kPu3sfPEcN/jctDGZOT6YM//IhAfBvEjHY0T+dw3GVQyX+DU+QlspWQHy10
57
+ hmsvKJPiV5t6qBPvZDTsizFGX8Yc6vsJ83TrU4FEJ7jgiU61o0BmTjNbC4DABjH4
58
+ byJ+44n4oQKBgE/k2+wkKHLH7ukcMLwnBeRnnfOAG9CD54FSAYIcfB+ER+WxrvnB
59
+ sOj8Q4Xol82euaItSkHiLbMikApJT21kwdhN083D+iupfaMD2fayo1I/UhIhHyFw
60
+ XkOqr1AYEYHItRnjIAeSx/d9CJKuseLS5tknZwP0m/4K7gT5KnrUAaeBAoGAea5M
61
+ 9NurVM/mz6GL2Vomye87enF8Qq/QzBLJZh/yuaeregYGrpLVu46lW+EALQwMWbk0
62
+ HvourasdQVYbK7uDaKTU99jzbdIJXNpYmNWWpRlnrO/VBYmy8E529SqmMLjDxNy+
63
+ yqMAVv5gVdr6S1lF6R2yfrTtQWfqvuVqLMAoLwECgYBm3LuwgYy3WANqgiPJKA6j
64
+ HzHsCVjdBTI1ALk3wpbcxnwosLlQG2OGovLBg4mv7/VH/uJuIesqQgT92aDlA3WJ
65
+ Lm1mYW/IvAn6cdBk5sWuVwq2mv7WV6RBj+aXLpgkWTfKPaeFjO3x5VcFfaUKgsbW
66
+ Cytule9R8gYnncv2bWZUCg==
67
+ -----END PRIVATE KEY-----`;
68
+
69
+ const PEMS_RSA_PUBLIC_KEY_PKCS1 = `-----BEGIN RSA PUBLIC KEY-----
70
+ MIIBCgKCAQEA5WykLKHiBAhmZh5WhocgpQQqZjdrApuRxRT21SJZx6Ce+Oz2V17/
71
+ heozu5LEz63jCxW1NrBckzl/Ys8p9LeqYTu6x/LbKloTjfEWxlzXnzUSqn9JHIxm
72
+ mJQzjXp9X1D99Tj+NWpRGEIiCFE7JfDhe2KnMGVDDg6kfCLokDdLo256LeQ4CEkV
73
+ iwY6d+at4xDlIHwvZZmG4Smk56eHhvQE3I8sSAzgoLMBamQ5m3MbiULAYtxskCpC
74
+ fjFxrL6Ziaaj7HZoneF40R30KCI9ygF8vkzxLwe3t5Y4XgHL9TYQm1+BDninupIB
75
+ /zTeO1ygBGA66m6zpmkmuG7d8HXIducz+wIDAQAB
76
+ -----END RSA PUBLIC KEY-----`;
77
+
78
+ const PEMS_RSA_PUBLIC_KEY_PKCS8 = `-----BEGIN PUBLIC KEY-----
79
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5WykLKHiBAhmZh5Whocg
80
+ pQQqZjdrApuRxRT21SJZx6Ce+Oz2V17/heozu5LEz63jCxW1NrBckzl/Ys8p9Leq
81
+ YTu6x/LbKloTjfEWxlzXnzUSqn9JHIxmmJQzjXp9X1D99Tj+NWpRGEIiCFE7JfDh
82
+ e2KnMGVDDg6kfCLokDdLo256LeQ4CEkViwY6d+at4xDlIHwvZZmG4Smk56eHhvQE
83
+ 3I8sSAzgoLMBamQ5m3MbiULAYtxskCpCfjFxrL6Ziaaj7HZoneF40R30KCI9ygF8
84
+ vkzxLwe3t5Y4XgHL9TYQm1+BDninupIB/zTeO1ygBGA66m6zpmkmuG7d8HXIducz
85
+ +wIDAQAB
86
+ -----END PUBLIC KEY-----`;
87
+
88
+ const PEMS_RSA_CERT = `-----BEGIN CERTIFICATE-----
89
+ MIIDGzCCAgOgAwIBAgIUROs52CB3BsvEVLOCtALalnJG8tEwDQYJKoZIhvcNAQEL
90
+ BQAwHTEbMBkGA1UEAwwSUlNBIDIwNDggUHVibGljS2V5MB4XDTIxMDQxMzIxMDE0
91
+ OVoXDTMxMDQxMTIxMDE0OVowHTEbMBkGA1UEAwwSUlNBIDIwNDggUHVibGljS2V5
92
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5WykLKHiBAhmZh5Whocg
93
+ pQQqZjdrApuRxRT21SJZx6Ce+Oz2V17/heozu5LEz63jCxW1NrBckzl/Ys8p9Leq
94
+ YTu6x/LbKloTjfEWxlzXnzUSqn9JHIxmmJQzjXp9X1D99Tj+NWpRGEIiCFE7JfDh
95
+ e2KnMGVDDg6kfCLokDdLo256LeQ4CEkViwY6d+at4xDlIHwvZZmG4Smk56eHhvQE
96
+ 3I8sSAzgoLMBamQ5m3MbiULAYtxskCpCfjFxrL6Ziaaj7HZoneF40R30KCI9ygF8
97
+ vkzxLwe3t5Y4XgHL9TYQm1+BDninupIB/zTeO1ygBGA66m6zpmkmuG7d8HXIducz
98
+ +wIDAQABo1MwUTAdBgNVHQ4EFgQUcRhRB6H5JqlDHbymwqydW2/EAt8wHwYDVR0j
99
+ BBgwFoAUcRhRB6H5JqlDHbymwqydW2/EAt8wDwYDVR0TAQH/BAUwAwEB/zANBgkq
100
+ hkiG9w0BAQsFAAOCAQEALXBmDizTp/Uz4M2A4nCl0AVclrXEk+YjAKqZnvtj44Gs
101
+ CUcpxtcXu64ppsSYCwawvzIm6B2Mdmib422aInH0e0oNrn8cRzC144Hjnzxguamj
102
+ LyZXnH/0wN9SAjqCKt++urH9wbRMIl0v+g4CWjGyY+eYkMmd1UMQvdCCCv6RVm56
103
+ 7dBCijJIHg23JbgPJD72JCluXtTYWllv3duSwuWeYHo5EftU456pDcztkgn9XwFk
104
+ PFGnHLmbjpSzjE7u29qCjwHl3CiUsjfUlYFl/mf27oDXPqaWqPYv3fWH3H3ymiZQ
105
+ cqptUF4hDtPkaNkKWFmlljChN92o8g/jrv4DVDgJzQ==
106
+ -----END CERTIFICATE-----`;
107
+
108
+ /** EC P-256 key pair and certificate */
109
+ const PEMS_EC_P256_PRIVATE_KEY = `-----BEGIN EC PRIVATE KEY-----
110
+ MHcCAQEEIIhdQxQIcMnCHD3X4WqNv+VgycWmFoEZpRl9X0+dT9uHoAoGCCqGSM49
111
+ AwEHoUQDQgAEFLQcBbzDweo6af4k3k0gKWMNWOZVn8+9hH2rv4DKKYZ7E1z64LBt
112
+ PnB1gMz++HDKySr2ozD3/46dIbQMXUZKpw==
113
+ -----END EC PRIVATE KEY-----`;
114
+
115
+ const PEMS_EC_P256_PRIVATE_KEY_PKCS8 = `-----BEGIN PRIVATE KEY-----
116
+ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiF1DFAhwycIcPdfh
117
+ ao2/5WDJxaYWgRmlGX1fT51P24ehRANCAAQUtBwFvMPB6jpp/iTeTSApYw1Y5lWf
118
+ z72Efau/gMophnsTXPrgsG0+cHWAzP74cMrJKvajMPf/jp0htAxdRkqn
119
+ -----END PRIVATE KEY-----`;
120
+
121
+ const PEMS_EC_P256_PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
122
+ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFLQcBbzDweo6af4k3k0gKWMNWOZV
123
+ n8+9hH2rv4DKKYZ7E1z64LBtPnB1gMz++HDKySr2ozD3/46dIbQMXUZKpw==
124
+ -----END PUBLIC KEY-----`;
125
+
126
+ const PEMS_FOO = `-----BEGIN FOO-----
127
+ Rk9P
128
+ -----END FOO-----`;
129
+ const PEMS_BAR = `-----BEGIN BAR-----
130
+ QkFS
131
+ -----END BAR-----`;
132
+
133
+ TestRegister.addTests([
134
+ {
135
+ name: "PEMtoHex: Nothing",
136
+ input: "",
137
+ expectedOutput: "",
138
+ recipeConfig: [
139
+ {
140
+ "op": "PEM to Hex",
141
+ "args": []
142
+ }
143
+ ]
144
+ },
145
+ {
146
+ name: "PEMtoHex: No footer",
147
+ input: PEMS_RSA_PRIVATE_KEY_PKCS1.substring(0, 200),
148
+ expectedOutput: "PEM footer '-----END RSA PRIVATE KEY-----' not found",
149
+ recipeConfig: [
150
+ {
151
+ "op": "PEM to Hex",
152
+ "args": []
153
+ }
154
+ ]
155
+ },
156
+ {
157
+ name: "PEMtoHex: Multiple PEMs",
158
+ input: PEMS_FOO + "\n" + PEMS_BAR,
159
+ expectedOutput: "FOOBAR",
160
+ recipeConfig: [
161
+ {
162
+ "op": "PEM to Hex",
163
+ "args": []
164
+ },
165
+ {
166
+ "op": "From Hex",
167
+ "args": ["Auto"]
168
+ }
169
+ ]
170
+ },
171
+ {
172
+ name: "PEMtoHex: Single line PEM",
173
+ input: PEMS_FOO.replace(/(\n|\r)/gm, ""),
174
+ expectedOutput: "FOO",
175
+ recipeConfig: [
176
+ {
177
+ "op": "PEM to Hex",
178
+ "args": []
179
+ },
180
+ {
181
+ "op": "From Hex",
182
+ "args": ["None"]
183
+ }
184
+ ]
185
+ },
186
+ {
187
+ name: "PEMtoHex: EC P-256 Private Key",
188
+ input: PEMS_EC_P256_PRIVATE_KEY,
189
+ expectedOutput: "30770201010420885d43140870c9c21c3dd7e16a8dbfe560c9c5a6168119a5197d5f4f9d4fdb87a00a06082a8648ce3d030107a1440342000414b41c05bcc3c1ea3a69fe24de4d2029630d58e6559fcfbd847dabbf80ca29867b135cfae0b06d3e707580ccfef870cac92af6a330f7ff8e9d21b40c5d464aa7",
190
+ recipeConfig: [
191
+ {
192
+ "op": "PEM to Hex",
193
+ "args": []
194
+ }
195
+ ]
196
+ },
197
+ {
198
+ name: "PEMtoHex: EC P-256 Private Key PKCS8",
199
+ input: PEMS_EC_P256_PRIVATE_KEY_PKCS8,
200
+ expectedOutput: "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420885d43140870c9c21c3dd7e16a8dbfe560c9c5a6168119a5197d5f4f9d4fdb87a1440342000414b41c05bcc3c1ea3a69fe24de4d2029630d58e6559fcfbd847dabbf80ca29867b135cfae0b06d3e707580ccfef870cac92af6a330f7ff8e9d21b40c5d464aa7",
201
+ recipeConfig: [
202
+ {
203
+ "op": "PEM to Hex",
204
+ "args": []
205
+ }
206
+ ]
207
+ },
208
+ {
209
+ name: "PEMtoHex: EC P-256 Public Key",
210
+ input: PEMS_EC_P256_PUBLIC_KEY,
211
+ expectedOutput: "3059301306072a8648ce3d020106082a8648ce3d0301070342000414b41c05bcc3c1ea3a69fe24de4d2029630d58e6559fcfbd847dabbf80ca29867b135cfae0b06d3e707580ccfef870cac92af6a330f7ff8e9d21b40c5d464aa7",
212
+ recipeConfig: [
213
+ {
214
+ "op": "PEM to Hex",
215
+ "args": []
216
+ }
217
+ ]
218
+ },
219
+ {
220
+ name: "PEMtoHex: RSA Private Key PKCS1",
221
+ input: PEMS_RSA_PRIVATE_KEY_PKCS1,
222
+ expectedOutput: "fb49bd96ffc5d1351a35d773921fac03",
223
+ recipeConfig: [
224
+ {
225
+ "op": "PEM to Hex",
226
+ "args": []
227
+ },
228
+ {
229
+ "op": "MD5",
230
+ "args": []
231
+ }
232
+ ]
233
+ },
234
+ {
235
+ name: "PEMtoHex: RSA Private Key PKCS8",
236
+ input: PEMS_RSA_PRIVATE_KEY_PKCS8,
237
+ expectedOutput: "23086d03633689fee64680c3c24409eb",
238
+ recipeConfig: [
239
+ {
240
+ "op": "PEM to Hex",
241
+ "args": []
242
+ },
243
+ {
244
+ "op": "MD5",
245
+ "args": []
246
+ }
247
+ ]
248
+ },
249
+ {
250
+ name: "PEMtoHex: RSA Public Key PKCS1",
251
+ input: PEMS_RSA_PUBLIC_KEY_PKCS1,
252
+ expectedOutput: "5fc3f1f6c5d5806760b12eaad0c0292c",
253
+ recipeConfig: [
254
+ {
255
+ "op": "PEM to Hex",
256
+ "args": []
257
+ },
258
+ {
259
+ "op": "MD5",
260
+ "args": []
261
+ }
262
+ ]
263
+ },
264
+ {
265
+ name: "PEMtoHex: RSA Public Key PKCS8",
266
+ input: PEMS_RSA_PUBLIC_KEY_PKCS8,
267
+ expectedOutput: "30fbe8e9495d591232affebdd6206ea6",
268
+ recipeConfig: [
269
+ {
270
+ "op": "PEM to Hex",
271
+ "args": []
272
+ },
273
+ {
274
+ "op": "MD5",
275
+ "args": []
276
+ }
277
+ ]
278
+ },
279
+ {
280
+ name: "PEMtoHex: Certificate",
281
+ input: PEMS_RSA_CERT,
282
+ expectedOutput: "6694d8ca4a0ceb84c3951d25dc05ec6e",
283
+ recipeConfig: [
284
+ {
285
+ "op": "PEM to Hex",
286
+ "args": []
287
+ },
288
+ {
289
+ "op": "MD5",
290
+ "args": []
291
+ }
292
+ ]
293
+ }
294
+ ]);