cyberchef 9.38.7 → 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.7",
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
  },
@@ -8580,7 +8585,7 @@
8580
8585
  "PEM to Hex": {
8581
8586
  "module": "Default",
8582
8587
  "description": "Converts PEM (Privacy Enhanced Mail) format to a hexadecimal DER (Distinguished Encoding Rules) string.",
8583
- "infoURL": "https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail#Format",
8588
+ "infoURL": "https://wikipedia.org/wiki/Privacy-Enhanced_Mail#Format",
8584
8589
  "inputType": "string",
8585
8590
  "outputType": "string",
8586
8591
  "flowControl": false,
@@ -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;
@@ -24,7 +24,7 @@ class PEMToHex extends Operation {
24
24
  this.name = "PEM to Hex";
25
25
  this.module = "Default";
26
26
  this.description = "Converts PEM (Privacy Enhanced Mail) format to a hexadecimal DER (Distinguished Encoding Rules) string.";
27
- this.infoURL = "https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail#Format";
27
+ this.infoURL = "https://wikipedia.org/wiki/Privacy-Enhanced_Mail#Format";
28
28
  this.inputType = "string";
29
29
  this.outputType = "string";
30
30
  this.args = [];
@@ -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
+ }
@@ -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
  ]);