mirror of
https://github.com/gchq/CyberChef.git
synced 2025-05-11 16:51:31 -04:00
125 lines
4.6 KiB
JavaScript
125 lines
4.6 KiB
JavaScript
/**
|
|
* @author n1474335 [n1474335@gmail.com]
|
|
* @copyright Crown Copyright 2022
|
|
* @license Apache-2.0
|
|
*
|
|
* In order to render whitespace characters as control character pictures in the output, even
|
|
* when they are the designated line separator, CyberChef sometimes chooses to represent them
|
|
* internally using the Unicode Private Use Area (https://en.wikipedia.org/wiki/Private_Use_Areas).
|
|
* See `Utils.escapeWhitespace()` for an example of this.
|
|
*
|
|
* The `renderSpecialChar()` function understands that it should display these characters as
|
|
* control pictures. When copying data from the Output, we need to replace these PUA characters
|
|
* with their original values, so we override the DOM "copy" event and modify the copied data
|
|
* if required. This handler is based closely on the built-in CodeMirror handler and defers to the
|
|
* built-in handler if PUA characters are not present in the copied data, in order to minimise the
|
|
* impact of breaking changes.
|
|
*/
|
|
|
|
import {EditorView} from "@codemirror/view";
|
|
|
|
/**
|
|
* Copies the currently selected text from the state doc.
|
|
* Based on the built-in implementation with a few unrequired bits taken out:
|
|
* https://github.com/codemirror/view/blob/7d9c3e54396242d17b3164a0e244dcc234ee50ee/src/input.ts#L604
|
|
*
|
|
* @param {EditorState} state
|
|
* @returns {Object}
|
|
*/
|
|
function copiedRange(state) {
|
|
const content = [];
|
|
let linewise = false;
|
|
for (const range of state.selection.ranges) if (!range.empty) {
|
|
content.push(state.sliceDoc(range.from, range.to));
|
|
}
|
|
if (!content.length) {
|
|
// Nothing selected, do a line-wise copy
|
|
let upto = -1;
|
|
for (const {from} of state.selection.ranges) {
|
|
const line = state.doc.lineAt(from);
|
|
if (line.number > upto) {
|
|
content.push(line.text);
|
|
}
|
|
upto = line.number;
|
|
}
|
|
linewise = true;
|
|
}
|
|
|
|
return {text: content.join(state.lineBreak), linewise};
|
|
}
|
|
|
|
/**
|
|
* Regex to match characters in the Private Use Area of the Unicode table.
|
|
*/
|
|
const PUARegex = new RegExp("[\ue000-\uf8ff]");
|
|
const PUARegexG = new RegExp("[\ue000-\uf8ff]", "g");
|
|
/**
|
|
* Regex tto match Unicode Control Pictures.
|
|
*/
|
|
const CPRegex = new RegExp("[\u2400-\u243f]");
|
|
const CPRegexG = new RegExp("[\u2400-\u243f]", "g");
|
|
|
|
/**
|
|
* Overrides the DOM "copy" handler in the CodeMirror editor in order to return the original
|
|
* values of control characters that have been represented in the Unicode Private Use Area for
|
|
* visual purposes.
|
|
* Based on the built-in copy handler with some modifications:
|
|
* https://github.com/codemirror/view/blob/7d9c3e54396242d17b3164a0e244dcc234ee50ee/src/input.ts#L629
|
|
*
|
|
* This handler will defer to the built-in version if no PUA characters are present.
|
|
*
|
|
* @returns {Extension}
|
|
*/
|
|
export function copyOverride() {
|
|
return EditorView.domEventHandlers({
|
|
copy(event, view) {
|
|
const {text, linewise} = copiedRange(view.state);
|
|
if (!text && !linewise) return;
|
|
|
|
// If there are no PUA chars in the copied text, return false and allow the built-in
|
|
// copy handler to fire
|
|
if (!PUARegex.test(text)) return false;
|
|
|
|
// If PUA chars are detected, modify them back to their original values and copy that instead
|
|
const rawText = text.replace(PUARegexG, function(c) {
|
|
return String.fromCharCode(c.charCodeAt(0) - 0xe000);
|
|
});
|
|
|
|
event.preventDefault();
|
|
event.clipboardData.clearData();
|
|
event.clipboardData.setData("text/plain", rawText);
|
|
|
|
// Returning true prevents CodeMirror default handlers from firing
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
/**
|
|
* Handler for copy events in output-html decorations. If there are control pictures present,
|
|
* this handler will convert them back to their raw form before copying. If there are no
|
|
* control pictures present, it will do nothing and defer to the default browser handler.
|
|
*
|
|
* @param {ClipboardEvent} event
|
|
* @returns {boolean}
|
|
*/
|
|
export function htmlCopyOverride(event) {
|
|
const text = window.getSelection().toString();
|
|
if (!text) return;
|
|
|
|
// If there are no control picture chars in the copied text, return false and allow the built-in
|
|
// copy handler to fire
|
|
if (!CPRegex.test(text)) return false;
|
|
|
|
// If control picture chars are detected, modify them back to their original values and copy that instead
|
|
const rawText = text.replace(CPRegexG, function(c) {
|
|
return String.fromCharCode(c.charCodeAt(0) - 0x2400);
|
|
});
|
|
|
|
event.preventDefault();
|
|
event.clipboardData.clearData();
|
|
event.clipboardData.setData("text/plain", rawText);
|
|
|
|
return true;
|
|
}
|