cyberchef 9.38.0 → 9.38.4
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 +3 -1
- package/src/core/config/OperationConfig.json +38 -16
- package/src/core/config/scripts/newMinorVersion.mjs +144 -0
- package/src/core/lib/Base64.mjs +44 -17
- package/src/core/lib/Binary.mjs +14 -12
- package/src/core/operations/FromBase64.mjs +24 -19
- package/src/core/operations/Substitute.mjs +5 -5
- package/src/core/operations/ToBase45.mjs +4 -0
- package/src/core/operations/ToHex.mjs +2 -2
- package/src/core/operations/ToUpperCase.mjs +22 -16
- package/src/web/App.mjs +10 -5
- package/src/web/html/index.html +12 -10
- package/src/web/stylesheets/components/_pane.css +11 -4
- package/src/web/stylesheets/layout/_controls.css +4 -0
- package/src/web/stylesheets/layout/_io.css +1 -2
- package/src/web/stylesheets/layout/_structure.css +2 -2
- package/src/web/waiters/OutputWaiter.mjs +2 -0
- package/src/web/waiters/WindowWaiter.mjs +2 -2
- package/tests/operations/tests/Magic.mjs +2 -2
- package/webpack.config.js +11 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cyberchef",
|
|
3
|
-
"version": "9.38.
|
|
3
|
+
"version": "9.38.4",
|
|
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",
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"html-webpack-plugin": "^5.5.0",
|
|
70
70
|
"imports-loader": "^3.1.1",
|
|
71
71
|
"mini-css-extract-plugin": "2.6.0",
|
|
72
|
+
"modify-source-webpack-plugin": "^3.0.0",
|
|
72
73
|
"nightwatch": "^2.0.10",
|
|
73
74
|
"postcss": "^8.4.12",
|
|
74
75
|
"postcss-css-variables": "^0.18.0",
|
|
@@ -174,6 +175,7 @@
|
|
|
174
175
|
"lint": "npx grunt lint",
|
|
175
176
|
"postinstall": "npx grunt exec:fixCryptoApiImports",
|
|
176
177
|
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
|
|
178
|
+
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs",
|
|
177
179
|
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
|
|
178
180
|
"setheapsize": "export NODE_OPTIONS=--max_old_space_size=2048"
|
|
179
181
|
}
|
|
@@ -5791,6 +5791,11 @@
|
|
|
5791
5791
|
"name": "Remove non-alphabet chars",
|
|
5792
5792
|
"type": "boolean",
|
|
5793
5793
|
"value": true
|
|
5794
|
+
},
|
|
5795
|
+
{
|
|
5796
|
+
"name": "Strict mode",
|
|
5797
|
+
"type": "boolean",
|
|
5798
|
+
"value": false
|
|
5794
5799
|
}
|
|
5795
5800
|
],
|
|
5796
5801
|
"checks": [
|
|
@@ -5799,7 +5804,8 @@
|
|
|
5799
5804
|
"flags": "i",
|
|
5800
5805
|
"args": [
|
|
5801
5806
|
"A-Za-z0-9+/=",
|
|
5802
|
-
true
|
|
5807
|
+
true,
|
|
5808
|
+
false
|
|
5803
5809
|
]
|
|
5804
5810
|
},
|
|
5805
5811
|
{
|
|
@@ -5807,7 +5813,8 @@
|
|
|
5807
5813
|
"flags": "i",
|
|
5808
5814
|
"args": [
|
|
5809
5815
|
"A-Za-z0-9-_",
|
|
5810
|
-
true
|
|
5816
|
+
true,
|
|
5817
|
+
false
|
|
5811
5818
|
]
|
|
5812
5819
|
},
|
|
5813
5820
|
{
|
|
@@ -5815,7 +5822,8 @@
|
|
|
5815
5822
|
"flags": "i",
|
|
5816
5823
|
"args": [
|
|
5817
5824
|
"A-Za-z0-9+\\-=",
|
|
5818
|
-
true
|
|
5825
|
+
true,
|
|
5826
|
+
false
|
|
5819
5827
|
]
|
|
5820
5828
|
},
|
|
5821
5829
|
{
|
|
@@ -5823,7 +5831,8 @@
|
|
|
5823
5831
|
"flags": "i",
|
|
5824
5832
|
"args": [
|
|
5825
5833
|
"./0-9A-Za-z=",
|
|
5826
|
-
true
|
|
5834
|
+
true,
|
|
5835
|
+
false
|
|
5827
5836
|
]
|
|
5828
5837
|
},
|
|
5829
5838
|
{
|
|
@@ -5831,7 +5840,8 @@
|
|
|
5831
5840
|
"flags": "i",
|
|
5832
5841
|
"args": [
|
|
5833
5842
|
"A-Za-z0-9_.",
|
|
5834
|
-
true
|
|
5843
|
+
true,
|
|
5844
|
+
false
|
|
5835
5845
|
]
|
|
5836
5846
|
},
|
|
5837
5847
|
{
|
|
@@ -5839,7 +5849,8 @@
|
|
|
5839
5849
|
"flags": "i",
|
|
5840
5850
|
"args": [
|
|
5841
5851
|
"A-Za-z0-9._-",
|
|
5842
|
-
true
|
|
5852
|
+
true,
|
|
5853
|
+
false
|
|
5843
5854
|
]
|
|
5844
5855
|
},
|
|
5845
5856
|
{
|
|
@@ -5847,7 +5858,8 @@
|
|
|
5847
5858
|
"flags": "i",
|
|
5848
5859
|
"args": [
|
|
5849
5860
|
"0-9a-zA-Z+/=",
|
|
5850
|
-
true
|
|
5861
|
+
true,
|
|
5862
|
+
false
|
|
5851
5863
|
]
|
|
5852
5864
|
},
|
|
5853
5865
|
{
|
|
@@ -5855,7 +5867,8 @@
|
|
|
5855
5867
|
"flags": "i",
|
|
5856
5868
|
"args": [
|
|
5857
5869
|
"0-9A-Za-z+/=",
|
|
5858
|
-
true
|
|
5870
|
+
true,
|
|
5871
|
+
false
|
|
5859
5872
|
]
|
|
5860
5873
|
},
|
|
5861
5874
|
{
|
|
@@ -5863,6 +5876,7 @@
|
|
|
5863
5876
|
"flags": "",
|
|
5864
5877
|
"args": [
|
|
5865
5878
|
" -_",
|
|
5879
|
+
false,
|
|
5866
5880
|
false
|
|
5867
5881
|
]
|
|
5868
5882
|
},
|
|
@@ -5871,7 +5885,8 @@
|
|
|
5871
5885
|
"flags": "i",
|
|
5872
5886
|
"args": [
|
|
5873
5887
|
"+\\-0-9A-Za-z",
|
|
5874
|
-
true
|
|
5888
|
+
true,
|
|
5889
|
+
false
|
|
5875
5890
|
]
|
|
5876
5891
|
},
|
|
5877
5892
|
{
|
|
@@ -5879,7 +5894,8 @@
|
|
|
5879
5894
|
"flags": "",
|
|
5880
5895
|
"args": [
|
|
5881
5896
|
"!-,-0-689@A-NP-VX-Z[`a-fh-mp-r",
|
|
5882
|
-
true
|
|
5897
|
+
true,
|
|
5898
|
+
false
|
|
5883
5899
|
]
|
|
5884
5900
|
},
|
|
5885
5901
|
{
|
|
@@ -5887,7 +5903,8 @@
|
|
|
5887
5903
|
"flags": "i",
|
|
5888
5904
|
"args": [
|
|
5889
5905
|
"N-ZA-Mn-za-m0-9+/=",
|
|
5890
|
-
true
|
|
5906
|
+
true,
|
|
5907
|
+
false
|
|
5891
5908
|
]
|
|
5892
5909
|
},
|
|
5893
5910
|
{
|
|
@@ -5895,7 +5912,8 @@
|
|
|
5895
5912
|
"flags": "i",
|
|
5896
5913
|
"args": [
|
|
5897
5914
|
"./0-9A-Za-z",
|
|
5898
|
-
true
|
|
5915
|
+
true,
|
|
5916
|
+
false
|
|
5899
5917
|
]
|
|
5900
5918
|
},
|
|
5901
5919
|
{
|
|
@@ -5903,7 +5921,8 @@
|
|
|
5903
5921
|
"flags": "i",
|
|
5904
5922
|
"args": [
|
|
5905
5923
|
"/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC",
|
|
5906
|
-
true
|
|
5924
|
+
true,
|
|
5925
|
+
false
|
|
5907
5926
|
]
|
|
5908
5927
|
},
|
|
5909
5928
|
{
|
|
@@ -5911,7 +5930,8 @@
|
|
|
5911
5930
|
"flags": "i",
|
|
5912
5931
|
"args": [
|
|
5913
5932
|
"3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5",
|
|
5914
|
-
true
|
|
5933
|
+
true,
|
|
5934
|
+
false
|
|
5915
5935
|
]
|
|
5916
5936
|
},
|
|
5917
5937
|
{
|
|
@@ -5919,7 +5939,8 @@
|
|
|
5919
5939
|
"flags": "i",
|
|
5920
5940
|
"args": [
|
|
5921
5941
|
"ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2",
|
|
5922
|
-
true
|
|
5942
|
+
true,
|
|
5943
|
+
false
|
|
5923
5944
|
]
|
|
5924
5945
|
},
|
|
5925
5946
|
{
|
|
@@ -5927,7 +5948,8 @@
|
|
|
5927
5948
|
"flags": "i",
|
|
5928
5949
|
"args": [
|
|
5929
5950
|
"HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5",
|
|
5930
|
-
true
|
|
5951
|
+
true,
|
|
5952
|
+
false
|
|
5931
5953
|
]
|
|
5932
5954
|
}
|
|
5933
5955
|
]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This script updates the CHANGELOG when a new minor version is created.
|
|
3
|
+
*
|
|
4
|
+
* @author n1474335 [n1474335@gmail.com]
|
|
5
|
+
* @copyright Crown Copyright 2022
|
|
6
|
+
* @license Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/* eslint no-console: ["off"] */
|
|
10
|
+
|
|
11
|
+
import prompt from "prompt";
|
|
12
|
+
import colors from "colors";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import fs from "fs";
|
|
15
|
+
import process from "process";
|
|
16
|
+
|
|
17
|
+
const dir = path.join(process.cwd() + "/src/core/config/");
|
|
18
|
+
if (!fs.existsSync(dir)) {
|
|
19
|
+
console.log("\nCWD: " + process.cwd());
|
|
20
|
+
console.log("Error: newMinorVersion.mjs should be run from the project root");
|
|
21
|
+
console.log("Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let changelogData = fs.readFileSync(path.join(process.cwd(), "CHANGELOG.md"), "utf8");
|
|
26
|
+
const lastVersion = changelogData.match(/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/);
|
|
27
|
+
const newVersion = [
|
|
28
|
+
parseInt(lastVersion[1], 10),
|
|
29
|
+
parseInt(lastVersion[2], 10) + 1,
|
|
30
|
+
0
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
let knownContributors = changelogData.match(/^\[@([^\]]+)\]/gm);
|
|
34
|
+
knownContributors = knownContributors.map(c => c.slice(2, -1));
|
|
35
|
+
|
|
36
|
+
const date = (new Date()).toISOString().split("T")[0];
|
|
37
|
+
|
|
38
|
+
const schema = {
|
|
39
|
+
properties: {
|
|
40
|
+
message: {
|
|
41
|
+
description: "A short but descriptive summary of a feature in this version",
|
|
42
|
+
example: "Added 'Op name' operation",
|
|
43
|
+
prompt: "Feature description",
|
|
44
|
+
type: "string",
|
|
45
|
+
required: true,
|
|
46
|
+
},
|
|
47
|
+
author: {
|
|
48
|
+
description: "The author of the feature (only one supported, edit manually to add more)",
|
|
49
|
+
example: "n1474335",
|
|
50
|
+
prompt: "Author",
|
|
51
|
+
type: "string",
|
|
52
|
+
default: "n1474335"
|
|
53
|
+
},
|
|
54
|
+
id: {
|
|
55
|
+
description: "The PR number or full commit hash for this feature.",
|
|
56
|
+
example: "1200",
|
|
57
|
+
prompt: "Pull request or commit ID",
|
|
58
|
+
type: "string"
|
|
59
|
+
},
|
|
60
|
+
another: {
|
|
61
|
+
description: "y/n",
|
|
62
|
+
example: "y",
|
|
63
|
+
prompt: "Add another feature?",
|
|
64
|
+
type: "string",
|
|
65
|
+
pattern: /^[yn]$/,
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// Build schema
|
|
71
|
+
for (const prop in schema.properties) {
|
|
72
|
+
const p = schema.properties[prop];
|
|
73
|
+
p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
prompt.message = "";
|
|
77
|
+
prompt.delimiter = ":".green;
|
|
78
|
+
|
|
79
|
+
const features = [];
|
|
80
|
+
const authors = [];
|
|
81
|
+
const prIDs = [];
|
|
82
|
+
const commitIDs = [];
|
|
83
|
+
|
|
84
|
+
prompt.start();
|
|
85
|
+
|
|
86
|
+
const getFeature = function() {
|
|
87
|
+
prompt.get(schema, (err, result) => {
|
|
88
|
+
if (err) {
|
|
89
|
+
console.log("\nExiting script.");
|
|
90
|
+
process.exit(0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
features.push(result);
|
|
94
|
+
|
|
95
|
+
if (result.another === "y") {
|
|
96
|
+
getFeature();
|
|
97
|
+
} else {
|
|
98
|
+
let message = `### [${newVersion[0]}.${newVersion[1]}.${newVersion[2]}] - ${date}\n`;
|
|
99
|
+
|
|
100
|
+
features.forEach(feature => {
|
|
101
|
+
const id = feature.id.length > 10 ? feature.id.slice(0, 7) : "#" + feature.id;
|
|
102
|
+
message += `- ${feature.message} [@${feature.author}] | [${id}]\n`;
|
|
103
|
+
|
|
104
|
+
if (!knownContributors.includes(feature.author)) {
|
|
105
|
+
authors.push(`[@${feature.author}]: https://github.com/${feature.author}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (feature.id.length > 10) {
|
|
109
|
+
commitIDs.push(`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`);
|
|
110
|
+
} else {
|
|
111
|
+
prIDs.push(`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Message
|
|
116
|
+
changelogData = changelogData.replace(/## Details\n\n/, "## Details\n\n" + message + "\n");
|
|
117
|
+
|
|
118
|
+
// Tag
|
|
119
|
+
const newTag = `[${newVersion[0]}.${newVersion[1]}.${newVersion[2]}]: https://github.com/gchq/CyberChef/releases/tag/v${newVersion[0]}.${newVersion[1]}.${newVersion[2]}\n`;
|
|
120
|
+
changelogData = changelogData.replace(/\n\n(\[\d+\.\d+\.\d+\]: https)/, "\n\n" + newTag + "$1");
|
|
121
|
+
|
|
122
|
+
// Author
|
|
123
|
+
authors.forEach(author => {
|
|
124
|
+
changelogData = changelogData.replace(/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/, "$1" + author + "\n\n");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Commit IDs
|
|
128
|
+
commitIDs.forEach(commitID => {
|
|
129
|
+
changelogData = changelogData.replace(/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/, "$1" + commitID + "\n\n");
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// PR IDs
|
|
133
|
+
prIDs.forEach(prID => {
|
|
134
|
+
changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n/, "$1" + prID + "\n\n");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData);
|
|
138
|
+
|
|
139
|
+
console.log("Written CHANGELOG.md");
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
getFeature();
|
package/src/core/lib/Base64.mjs
CHANGED
|
@@ -82,47 +82,74 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
|
|
|
82
82
|
* // returns [72, 101, 108, 108, 111]
|
|
83
83
|
* fromBase64("SGVsbG8=", null, "byteArray");
|
|
84
84
|
*/
|
|
85
|
-
export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true) {
|
|
85
|
+
export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true, strictMode=false) {
|
|
86
86
|
if (!data) {
|
|
87
87
|
return returnType === "string" ? "" : [];
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
alphabet = alphabet || "A-Za-z0-9+/=";
|
|
91
91
|
alphabet = Utils.expandAlphRange(alphabet).join("");
|
|
92
|
+
|
|
93
|
+
// Confirm alphabet is a valid length
|
|
92
94
|
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
|
|
93
|
-
throw new OperationError(`
|
|
95
|
+
throw new OperationError(`Error: Base64 alphabet should be 64 characters long, or 65 with a padding character. Found ${alphabet.length}: ${alphabet}`);
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
|
|
97
|
-
let chr1, chr2, chr3,
|
|
98
|
-
enc1, enc2, enc3, enc4,
|
|
99
|
-
i = 0;
|
|
100
|
-
|
|
98
|
+
// Remove non-alphabet characters
|
|
101
99
|
if (removeNonAlphChars) {
|
|
102
100
|
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
|
103
101
|
data = data.replace(re, "");
|
|
104
102
|
}
|
|
105
103
|
|
|
104
|
+
if (strictMode) {
|
|
105
|
+
// Check for incorrect lengths (even without padding)
|
|
106
|
+
if (data.length % 4 === 1) {
|
|
107
|
+
throw new OperationError(`Error: Invalid Base64 input length (${data.length}). Cannot be 4n+1, even without padding chars.`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (alphabet.length === 65) { // Padding character included
|
|
111
|
+
const pad = alphabet.charAt(64);
|
|
112
|
+
const padPos = data.indexOf(pad);
|
|
113
|
+
if (padPos >= 0) {
|
|
114
|
+
// Check that the padding character is only used at the end and maximum of twice
|
|
115
|
+
if (padPos < data.length - 2 || data.charAt(data.length - 1) !== pad) {
|
|
116
|
+
throw new OperationError(`Error: Base64 padding character (${pad}) not used in the correct place.`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check that input is padded to the correct length
|
|
120
|
+
if (data.length % 4 !== 0) {
|
|
121
|
+
throw new OperationError("Error: Base64 not padded to a multiple of 4.");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const output = [];
|
|
128
|
+
let chr1, chr2, chr3,
|
|
129
|
+
enc1, enc2, enc3, enc4,
|
|
130
|
+
i = 0;
|
|
131
|
+
|
|
106
132
|
while (i < data.length) {
|
|
107
133
|
enc1 = alphabet.indexOf(data.charAt(i++));
|
|
108
|
-
enc2 = alphabet.indexOf(data.charAt(i++)
|
|
109
|
-
enc3 = alphabet.indexOf(data.charAt(i++)
|
|
110
|
-
enc4 = 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++));
|
|
111
137
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
138
|
+
if (strictMode && (enc1 < 0 || enc2 < 0 || enc3 < 0 || enc4 < 0)) {
|
|
139
|
+
throw new OperationError("Error: Base64 input contains non-alphabet char(s)");
|
|
140
|
+
}
|
|
115
141
|
|
|
116
142
|
chr1 = (enc1 << 2) | (enc2 >> 4);
|
|
117
143
|
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
|
118
144
|
chr3 = ((enc3 & 3) << 6) | enc4;
|
|
119
145
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
146
|
+
if (chr1 < 256) {
|
|
147
|
+
output.push(chr1);
|
|
148
|
+
}
|
|
149
|
+
if (chr2 < 256 && enc3 !== 64) {
|
|
123
150
|
output.push(chr2);
|
|
124
151
|
}
|
|
125
|
-
if (enc4 !== 64) {
|
|
152
|
+
if (chr3 < 256 && enc4 !== 64) {
|
|
126
153
|
output.push(chr3);
|
|
127
154
|
}
|
|
128
155
|
}
|
package/src/core/lib/Binary.mjs
CHANGED
|
@@ -19,31 +19,33 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
19
19
|
* @returns {string}
|
|
20
20
|
*
|
|
21
21
|
* @example
|
|
22
|
-
* // returns "
|
|
22
|
+
* // returns "00001010 00010100 00011110"
|
|
23
23
|
* toBinary([10,20,30]);
|
|
24
24
|
*
|
|
25
|
-
* // returns "
|
|
26
|
-
* toBinary([10,20,30], "
|
|
25
|
+
* // returns "00001010:00010100:00011110"
|
|
26
|
+
* toBinary([10,20,30], "Colon");
|
|
27
|
+
*
|
|
28
|
+
* // returns "1010:10100:11110"
|
|
29
|
+
* toBinary([10,20,30], "Colon", 0);
|
|
27
30
|
*/
|
|
28
31
|
export function toBinary(data, delim="Space", padding=8) {
|
|
32
|
+
if (data === undefined || data === null)
|
|
33
|
+
throw new OperationError("Unable to convert to binary: Empty input data enocuntered");
|
|
34
|
+
|
|
29
35
|
delim = Utils.charRep(delim);
|
|
30
36
|
let output = "";
|
|
31
37
|
|
|
32
38
|
if (data.length) { // array
|
|
33
39
|
for (let i = 0; i < data.length; i++) {
|
|
34
|
-
output += data[i].toString(2).padStart(padding, "0")
|
|
40
|
+
output += data[i].toString(2).padStart(padding, "0");
|
|
41
|
+
if (i !== data.length - 1) output += delim;
|
|
35
42
|
}
|
|
36
43
|
} else if (typeof data === "number") { // Single value
|
|
37
44
|
return data.toString(2).padStart(padding, "0");
|
|
38
45
|
} else {
|
|
39
46
|
return "";
|
|
40
47
|
}
|
|
41
|
-
|
|
42
|
-
if (delim.length) {
|
|
43
|
-
return output.slice(0, -delim.length);
|
|
44
|
-
} else {
|
|
45
|
-
return output;
|
|
46
|
-
}
|
|
48
|
+
return output;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
|
|
@@ -57,10 +59,10 @@ export function toBinary(data, delim="Space", padding=8) {
|
|
|
57
59
|
*
|
|
58
60
|
* @example
|
|
59
61
|
* // returns [10,20,30]
|
|
60
|
-
* fromBinary("
|
|
62
|
+
* fromBinary("00001010 00010100 00011110");
|
|
61
63
|
*
|
|
62
64
|
* // returns [10,20,30]
|
|
63
|
-
* fromBinary("
|
|
65
|
+
* fromBinary("00001010:00010100:00011110", "Colon");
|
|
64
66
|
*/
|
|
65
67
|
export function fromBinary(data, delim="Space", byteLen=8) {
|
|
66
68
|
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
|
|
@@ -34,93 +34,98 @@ class FromBase64 extends Operation {
|
|
|
34
34
|
name: "Remove non-alphabet chars",
|
|
35
35
|
type: "boolean",
|
|
36
36
|
value: true
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "Strict mode",
|
|
40
|
+
type: "boolean",
|
|
41
|
+
value: false
|
|
37
42
|
}
|
|
38
43
|
];
|
|
39
44
|
this.checks = [
|
|
40
45
|
{
|
|
41
46
|
pattern: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
|
42
47
|
flags: "i",
|
|
43
|
-
args: ["A-Za-z0-9+/=", true]
|
|
48
|
+
args: ["A-Za-z0-9+/=", true, false]
|
|
44
49
|
},
|
|
45
50
|
{
|
|
46
51
|
pattern: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
|
|
47
52
|
flags: "i",
|
|
48
|
-
args: ["A-Za-z0-9-_", true]
|
|
53
|
+
args: ["A-Za-z0-9-_", true, false]
|
|
49
54
|
},
|
|
50
55
|
{
|
|
51
56
|
pattern: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
|
|
52
57
|
flags: "i",
|
|
53
|
-
args: ["A-Za-z0-9+\\-=", true]
|
|
58
|
+
args: ["A-Za-z0-9+\\-=", true, false]
|
|
54
59
|
},
|
|
55
60
|
{
|
|
56
61
|
pattern: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
|
|
57
62
|
flags: "i",
|
|
58
|
-
args: ["./0-9A-Za-z=", true]
|
|
63
|
+
args: ["./0-9A-Za-z=", true, false]
|
|
59
64
|
},
|
|
60
65
|
{
|
|
61
66
|
pattern: "^\\s*[A-Z\\d_.]{20,}\\s*$",
|
|
62
67
|
flags: "i",
|
|
63
|
-
args: ["A-Za-z0-9_.", true]
|
|
68
|
+
args: ["A-Za-z0-9_.", true, false]
|
|
64
69
|
},
|
|
65
70
|
{
|
|
66
71
|
pattern: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
|
|
67
72
|
flags: "i",
|
|
68
|
-
args: ["A-Za-z0-9._-", true]
|
|
73
|
+
args: ["A-Za-z0-9._-", true, false]
|
|
69
74
|
},
|
|
70
75
|
{
|
|
71
76
|
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
|
72
77
|
flags: "i",
|
|
73
|
-
args: ["0-9a-zA-Z+/=", true]
|
|
78
|
+
args: ["0-9a-zA-Z+/=", true, false]
|
|
74
79
|
},
|
|
75
80
|
{
|
|
76
81
|
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
|
77
82
|
flags: "i",
|
|
78
|
-
args: ["0-9A-Za-z+/=", true]
|
|
83
|
+
args: ["0-9A-Za-z+/=", true, false]
|
|
79
84
|
},
|
|
80
85
|
{
|
|
81
86
|
pattern: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
|
|
82
87
|
flags: "",
|
|
83
|
-
args: [" -_", false]
|
|
88
|
+
args: [" -_", false, false]
|
|
84
89
|
},
|
|
85
90
|
{
|
|
86
91
|
pattern: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
|
|
87
92
|
flags: "i",
|
|
88
|
-
args: ["+\\-0-9A-Za-z", true]
|
|
93
|
+
args: ["+\\-0-9A-Za-z", true, false]
|
|
89
94
|
},
|
|
90
95
|
{
|
|
91
96
|
pattern: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
|
|
92
97
|
flags: "",
|
|
93
|
-
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
|
|
98
|
+
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true, false]
|
|
94
99
|
},
|
|
95
100
|
{
|
|
96
101
|
pattern: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
|
|
97
102
|
flags: "i",
|
|
98
|
-
args: ["N-ZA-Mn-za-m0-9+/=", true]
|
|
103
|
+
args: ["N-ZA-Mn-za-m0-9+/=", true, false]
|
|
99
104
|
},
|
|
100
105
|
{
|
|
101
106
|
pattern: "^\\s*[A-Z\\d./]{20,}\\s*$",
|
|
102
107
|
flags: "i",
|
|
103
|
-
args: ["./0-9A-Za-z", true]
|
|
108
|
+
args: ["./0-9A-Za-z", true, false]
|
|
104
109
|
},
|
|
105
110
|
{
|
|
106
111
|
pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}CC|[A-Z=\\d\\+/]{3}C)?\\s*$",
|
|
107
112
|
flags: "i",
|
|
108
|
-
args: ["/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", true]
|
|
113
|
+
args: ["/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", true, false]
|
|
109
114
|
},
|
|
110
115
|
{
|
|
111
116
|
pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}55|[A-Z=\\d\\+/]{3}5)?\\s*$",
|
|
112
117
|
flags: "i",
|
|
113
|
-
args: ["3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", true]
|
|
118
|
+
args: ["3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", true, false]
|
|
114
119
|
},
|
|
115
120
|
{
|
|
116
121
|
pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}22|[A-Z=\\d\\+/]{3}2)?\\s*$",
|
|
117
122
|
flags: "i",
|
|
118
|
-
args: ["ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", true]
|
|
123
|
+
args: ["ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", true, false]
|
|
119
124
|
},
|
|
120
125
|
{
|
|
121
126
|
pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}55|[A-Z=\\d\\+/]{3}5)?\\s*$",
|
|
122
127
|
flags: "i",
|
|
123
|
-
args: ["HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", true]
|
|
128
|
+
args: ["HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", true, false]
|
|
124
129
|
}
|
|
125
130
|
];
|
|
126
131
|
}
|
|
@@ -131,9 +136,9 @@ class FromBase64 extends Operation {
|
|
|
131
136
|
* @returns {byteArray}
|
|
132
137
|
*/
|
|
133
138
|
run(input, args) {
|
|
134
|
-
const [alphabet, removeNonAlphChars] = args;
|
|
139
|
+
const [alphabet, removeNonAlphChars, strictMode] = args;
|
|
135
140
|
|
|
136
|
-
return fromBase64(input, alphabet, "byteArray", removeNonAlphChars);
|
|
141
|
+
return fromBase64(input, alphabet, "byteArray", removeNonAlphChars, strictMode);
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
/**
|
|
@@ -44,8 +44,8 @@ class Substitute extends Operation {
|
|
|
44
44
|
* @returns {string}
|
|
45
45
|
*/
|
|
46
46
|
run(input, args) {
|
|
47
|
-
const plaintext = Utils.expandAlphRange(args[0])
|
|
48
|
-
ciphertext = Utils.expandAlphRange(args[1])
|
|
47
|
+
const plaintext = Utils.expandAlphRange([...args[0]]),
|
|
48
|
+
ciphertext = Utils.expandAlphRange([...args[1]]);
|
|
49
49
|
let output = "",
|
|
50
50
|
index = -1;
|
|
51
51
|
|
|
@@ -53,9 +53,9 @@ class Substitute extends Operation {
|
|
|
53
53
|
output = "Warning: Plaintext and Ciphertext lengths differ\n\n";
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
for (
|
|
57
|
-
index = plaintext.indexOf(
|
|
58
|
-
output += index > -1 && index < ciphertext.length ? ciphertext[index] :
|
|
56
|
+
for (const character of input) {
|
|
57
|
+
index = plaintext.indexOf(character);
|
|
58
|
+
output += index > -1 && index < ciphertext.length ? ciphertext[index] : character;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
return output;
|
|
@@ -67,7 +67,7 @@ class ToHex extends Operation {
|
|
|
67
67
|
* @returns {Object[]} pos
|
|
68
68
|
*/
|
|
69
69
|
highlight(pos, args) {
|
|
70
|
-
let delim, commaLen;
|
|
70
|
+
let delim, commaLen = 0;
|
|
71
71
|
if (args[0] === "0x with comma") {
|
|
72
72
|
delim = "0x";
|
|
73
73
|
commaLen = 1;
|
|
@@ -86,7 +86,7 @@ class ToHex extends Operation {
|
|
|
86
86
|
pos[0].start = pos[0].start * (2 + len) + countLF(pos[0].start);
|
|
87
87
|
pos[0].end = pos[0].end * (2 + len) + countLF(pos[0].end);
|
|
88
88
|
|
|
89
|
-
// if the
|
|
89
|
+
// if the delimiters are not prepended, trim the trailing delimiter
|
|
90
90
|
if (!(delim === "0x" || delim === "\\x")) {
|
|
91
91
|
pos[0].end -= delim.length;
|
|
92
92
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import Operation from "../Operation.mjs";
|
|
8
|
+
import OperationError from "../errors/OperationError.mjs";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* To Upper case operation
|
|
@@ -37,25 +38,30 @@ class ToUpperCase extends Operation {
|
|
|
37
38
|
* @returns {string}
|
|
38
39
|
*/
|
|
39
40
|
run(input, args) {
|
|
41
|
+
if (!args || args.length === 0) {
|
|
42
|
+
throw new OperationError("No capitalization scope was provided.");
|
|
43
|
+
}
|
|
44
|
+
|
|
40
45
|
const scope = args[0];
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
55
|
-
case "All": /* falls through */
|
|
56
|
-
default:
|
|
57
|
-
return input.toUpperCase();
|
|
47
|
+
if (scope === "All") {
|
|
48
|
+
return input.toUpperCase();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const scopeRegex = {
|
|
52
|
+
"Word": /(\b\w)/gi,
|
|
53
|
+
"Sentence": /(?:\.|^)\s*(\b\w)/gi,
|
|
54
|
+
"Paragraph": /(?:\n|^)\s*(\b\w)/gi
|
|
55
|
+
}[scope];
|
|
56
|
+
|
|
57
|
+
if (scopeRegex === undefined) {
|
|
58
|
+
throw new OperationError("Unrecognized capitalization scope");
|
|
58
59
|
}
|
|
60
|
+
|
|
61
|
+
// Use the regex to capitalize the input
|
|
62
|
+
return input.replace(scopeRegex, function(m) {
|
|
63
|
+
return m.toUpperCase();
|
|
64
|
+
});
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
/**
|
package/src/web/App.mjs
CHANGED
|
@@ -57,7 +57,7 @@ class App {
|
|
|
57
57
|
this.populateOperationsList();
|
|
58
58
|
this.manager.setup();
|
|
59
59
|
this.manager.output.saveBombe();
|
|
60
|
-
this.
|
|
60
|
+
this.adjustComponentSizes();
|
|
61
61
|
this.setCompileMessage();
|
|
62
62
|
|
|
63
63
|
log.debug("App loaded");
|
|
@@ -295,9 +295,7 @@ class App {
|
|
|
295
295
|
gutterSize: 4,
|
|
296
296
|
expandToMin: true,
|
|
297
297
|
onDrag: debounce(function() {
|
|
298
|
-
this.
|
|
299
|
-
this.manager.input.calcMaxTabs();
|
|
300
|
-
this.manager.output.calcMaxTabs();
|
|
298
|
+
this.adjustComponentSizes();
|
|
301
299
|
}, 50, "dragSplitter", this, [])
|
|
302
300
|
});
|
|
303
301
|
|
|
@@ -307,7 +305,7 @@ class App {
|
|
|
307
305
|
minSize: minimise ? [0, 0] : [100, 100]
|
|
308
306
|
});
|
|
309
307
|
|
|
310
|
-
this.
|
|
308
|
+
this.adjustComponentSizes();
|
|
311
309
|
}
|
|
312
310
|
|
|
313
311
|
|
|
@@ -581,6 +579,13 @@ class App {
|
|
|
581
579
|
resetLayout() {
|
|
582
580
|
this.columnSplitter.setSizes([20, 30, 50]);
|
|
583
581
|
this.ioSplitter.setSizes([50, 50]);
|
|
582
|
+
this.adjustComponentSizes();
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Adjust components to fit their containers.
|
|
587
|
+
*/
|
|
588
|
+
adjustComponentSizes() {
|
|
584
589
|
this.manager.recipe.adjustWidth();
|
|
585
590
|
this.manager.input.calcMaxTabs();
|
|
586
591
|
this.manager.output.calcMaxTabs();
|
package/src/web/html/index.html
CHANGED
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
<div id="recipe" class="split split-horizontal no-select">
|
|
177
177
|
<div class="title no-select">
|
|
178
178
|
Recipe
|
|
179
|
-
<span class="
|
|
179
|
+
<span class="pane-controls hide-on-maximised-output">
|
|
180
180
|
<button type="button" class="btn btn-primary bmd-btn-icon" id="save" data-toggle="tooltip" title="Save recipe">
|
|
181
181
|
<i class="material-icons">save</i>
|
|
182
182
|
</button>
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
</div>
|
|
191
191
|
<ul id="rec-list" class="list-area no-select"></ul>
|
|
192
192
|
|
|
193
|
-
<div id="controls" class="no-select">
|
|
193
|
+
<div id="controls" class="no-select hide-on-maximised-output">
|
|
194
194
|
<div id="controls-content" class="d-flex align-items-center">
|
|
195
195
|
<button type="button" class="mx-2 btn btn-lg btn-secondary" id="step" data-toggle="tooltip" title="Step through the recipe">
|
|
196
196
|
Step
|
|
@@ -217,7 +217,10 @@
|
|
|
217
217
|
<div id="input" class="split no-select">
|
|
218
218
|
<div class="title no-select">
|
|
219
219
|
<label for="input-text">Input</label>
|
|
220
|
-
<span class="
|
|
220
|
+
<span class="pane-controls">
|
|
221
|
+
<div class="io-info" id="input-files-info"></div>
|
|
222
|
+
<div class="io-info" id="input-selection-info"></div>
|
|
223
|
+
<div class="io-info" id="input-info"></div>
|
|
221
224
|
<button type="button" class="btn btn-primary bmd-btn-icon" id="btn-new-tab" data-toggle="tooltip" title="Add a new input tab">
|
|
222
225
|
<i class="material-icons">add</i>
|
|
223
226
|
</button>
|
|
@@ -236,9 +239,7 @@
|
|
|
236
239
|
<i class="material-icons">view_compact</i>
|
|
237
240
|
</button>
|
|
238
241
|
</span>
|
|
239
|
-
|
|
240
|
-
<div class="io-info" id="input-info"></div>
|
|
241
|
-
<div class="io-info" id="input-selection-info"></div>
|
|
242
|
+
|
|
242
243
|
</div>
|
|
243
244
|
<div id="input-tabs-wrapper" style="display: none;" class="no-select">
|
|
244
245
|
<span id="btn-previous-input-tab" class="input-tab-buttons">
|
|
@@ -288,7 +289,10 @@
|
|
|
288
289
|
<div id="output" class="split">
|
|
289
290
|
<div class="title no-select">
|
|
290
291
|
<label for="output-text">Output</label>
|
|
291
|
-
<span class="
|
|
292
|
+
<span class="pane-controls">
|
|
293
|
+
<div class="io-info" id="bake-info"></div>
|
|
294
|
+
<div class="io-info" id="output-selection-info"></div>
|
|
295
|
+
<div class="io-info" id="output-info"></div>
|
|
292
296
|
<button type="button" class="btn btn-primary bmd-btn-icon" id="save-all-to-file" data-toggle="tooltip" title="Save all outputs to a zip file" style="display: none">
|
|
293
297
|
<i class="material-icons">archive</i>
|
|
294
298
|
</button>
|
|
@@ -308,9 +312,7 @@
|
|
|
308
312
|
<i class="material-icons">fullscreen</i>
|
|
309
313
|
</button>
|
|
310
314
|
</span>
|
|
311
|
-
|
|
312
|
-
<div class="io-info" id="output-info"></div>
|
|
313
|
-
<div class="io-info" id="output-selection-info"></div>
|
|
315
|
+
|
|
314
316
|
<button type="button" class="btn btn-primary bmd-btn-icon hidden" id="magic" data-toggle="tooltip" title="Magic!" data-html="true">
|
|
315
317
|
<svg width="22" height="22" viewBox="0 0 24 24">
|
|
316
318
|
<path d="M7.5,5.6L5,7L6.4,4.5L5,2L7.5,3.4L10,2L8.6,4.5L10,7L7.5,5.6M19.5,15.4L22,14L20.6,16.5L22,19L19.5,17.6L17,19L18.4,16.5L17,14L19.5,15.4M22,2L20.6,4.5L22,7L19.5,5.6L17,7L18.4,4.5L17,2L19.5,3.4L22,2M13.34,12.78L15.78,10.34L13.66,8.22L11.22,10.66L13.34,12.78M14.37,7.29L16.71,9.63C17.1,10 17.1,10.65 16.71,11.04L5.04,22.71C4.65,23.1 4,23.1 3.63,22.71L1.29,20.37C0.9,20 0.9,19.35 1.29,18.96L12.96,7.29C13.35,6.9 14,6.9 14.37,7.29Z" />
|
|
@@ -24,9 +24,16 @@
|
|
|
24
24
|
line-height: calc(var(--title-height) - 14px);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
.
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
.pane-controls {
|
|
28
|
+
position: absolute;
|
|
29
|
+
right: 8px;
|
|
30
|
+
top: 8px;
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: row;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.pane-controls .btn {
|
|
36
|
+
margin-left: 2px;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
.list-area {
|
|
@@ -107,4 +114,4 @@
|
|
|
107
114
|
|
|
108
115
|
#files .card-header .float-right a:hover {
|
|
109
116
|
text-decoration: none;
|
|
110
|
-
}
|
|
117
|
+
}
|
|
@@ -39,8 +39,8 @@ div#output {
|
|
|
39
39
|
|
|
40
40
|
.split {
|
|
41
41
|
box-sizing: border-box;
|
|
42
|
-
/* overflow: auto;
|
|
43
|
-
Removed to enable Background Magic button pulse to overflow.
|
|
42
|
+
/* overflow: auto; */
|
|
43
|
+
/* Removed to enable Background Magic button pulse to overflow.
|
|
44
44
|
Replace this rule if it seems to be causing problems. */
|
|
45
45
|
position: relative;
|
|
46
46
|
}
|
|
@@ -1373,6 +1373,7 @@ class OutputWaiter {
|
|
|
1373
1373
|
const el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;
|
|
1374
1374
|
|
|
1375
1375
|
if (el.getAttribute("data-original-title").indexOf("Maximise") === 0) {
|
|
1376
|
+
document.body.classList.add("output-maximised");
|
|
1376
1377
|
this.app.initialiseSplitter(true);
|
|
1377
1378
|
this.app.columnSplitter.collapse(0);
|
|
1378
1379
|
this.app.columnSplitter.collapse(1);
|
|
@@ -1381,6 +1382,7 @@ class OutputWaiter {
|
|
|
1381
1382
|
$(el).attr("data-original-title", "Restore output pane");
|
|
1382
1383
|
el.querySelector("i").innerHTML = "fullscreen_exit";
|
|
1383
1384
|
} else {
|
|
1385
|
+
document.body.classList.remove("output-maximised");
|
|
1384
1386
|
$(el).attr("data-original-title", "Maximise output pane");
|
|
1385
1387
|
el.querySelector("i").innerHTML = "fullscreen";
|
|
1386
1388
|
this.app.initialiseSplitter(false);
|
|
@@ -23,11 +23,11 @@ class WindowWaiter {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Handler for window resize events.
|
|
26
|
-
* Resets
|
|
26
|
+
* Resets adjustable component sizes after 200ms (so that continuous resizing doesn't cause
|
|
27
27
|
* continuous resetting).
|
|
28
28
|
*/
|
|
29
29
|
windowResize() {
|
|
30
|
-
debounce(this.app.
|
|
30
|
+
debounce(this.app.adjustComponentSizes, 200, "windowResize", this.app, [])();
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
|
|
@@ -68,7 +68,7 @@ TestRegister.addTests([
|
|
|
68
68
|
{
|
|
69
69
|
name: "Magic Chain: Base64",
|
|
70
70
|
input: "WkVkV2VtUkRRbnBrU0Vwd1ltMWpQUT09",
|
|
71
|
-
expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Base64\('A-Za-z0-9\+\/=',true\)/,
|
|
71
|
+
expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Base64\('A-Za-z0-9\+\/=',true,false\)/,
|
|
72
72
|
recipeConfig: [
|
|
73
73
|
{
|
|
74
74
|
op: "Magic",
|
|
@@ -79,7 +79,7 @@ TestRegister.addTests([
|
|
|
79
79
|
{
|
|
80
80
|
name: "Magic Chain: Hex -> Hexdump -> Base64",
|
|
81
81
|
input: "MDAwMDAwMDAgIDM3IDM0IDIwIDM2IDM1IDIwIDM3IDMzIDIwIDM3IDM0IDIwIDMyIDMwIDIwIDM3ICB8NzQgNjUgNzMgNzQgMjAgN3wKMDAwMDAwMTAgIDMzIDIwIDM3IDM0IDIwIDM3IDMyIDIwIDM2IDM5IDIwIDM2IDY1IDIwIDM2IDM3ICB8MyA3NCA3MiA2OSA2ZSA2N3w=",
|
|
82
|
-
expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Hexdump\(\)\nFrom_Hex\('Space'\)/,
|
|
82
|
+
expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Hexdump\(\)\nFrom_Hex\('Space'\)/,
|
|
83
83
|
recipeConfig: [
|
|
84
84
|
{
|
|
85
85
|
op: "Magic",
|
package/webpack.config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const webpack = require("webpack");
|
|
2
2
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
|
3
3
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
|
4
|
+
const { ModifySourcePlugin } = require("modify-source-webpack-plugin");
|
|
4
5
|
const path = require("path");
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -82,6 +83,16 @@ module.exports = {
|
|
|
82
83
|
to: "assets/forge/"
|
|
83
84
|
}
|
|
84
85
|
]
|
|
86
|
+
}),
|
|
87
|
+
new ModifySourcePlugin({
|
|
88
|
+
rules: [
|
|
89
|
+
{
|
|
90
|
+
// Fix toSpare(0) bug in Split.js by avoiding gutter accomodation
|
|
91
|
+
test: /split\.es\.js$/,
|
|
92
|
+
modify: (src, path) =>
|
|
93
|
+
src.replace("if (pixelSize < elementMinSize)", "if (false)")
|
|
94
|
+
}
|
|
95
|
+
]
|
|
85
96
|
})
|
|
86
97
|
],
|
|
87
98
|
resolve: {
|