Skip to content

Commit

Permalink
Merge pull request #60 from horihiro/bump-0.2.3
Browse files Browse the repository at this point in the history
Bump 0.2.3
  • Loading branch information
horihiro authored May 1, 2024
2 parents d28840c + f090162 commit f90997e
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 30 deletions.
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,42 @@ If you can try a development version, the following steps are needed.
![image](https://github.com/horihiro/TextBlurrer-ChromeExtension/assets/4566555/44e7f896-9e82-4af1-ae1b-f864097b44c7)
1. select the directory created by cloning at step 1.

# Limitations
- These are **experimental** features
- Input Element blurring
- Tab title masking
- The following HTML elements are not supported:
- HTML Canvas
- Inside of `contentEditable` element
- Web Terminal based on Xterm.js:
see [here](./docs/BLUR_ON_XTERMJS.md)
- Web Editor based on CodeMirror:
CodeMirror, which bases GitHub code editor, repairs its own contents automatically after blurring by this extension. Then blurring and repairing are repeated, it causes infinity loop. ([#62](https://github.com/horihiro/TextBlurrer-ChromeExtension/issues/62))

# Dependencies
- **[jsdiff](https://github.com/kpdecker/jsdiff)**: A JavaScript text differencing implementation (BSD 3-Clause License).
- **[jsdiff](https://github.com/kpdecker/jsdiff)**: A JavaScript text differencing implementation (BSD 3-Clause License).

# Change logs

## [0.2.3](https://github.com/horihiro/TextBlurrer-ChromeExtension/releases/tag/0.2.3)

- Bug fixes
- Fix tab title masking ([#56](https://github.com/horihiro/TextBlurrer-ChromeExtension/issues/56))
- Fix white-space handling ([#57](https://github.com/horihiro/TextBlurrer-ChromeExtension/issues/57))
- Fix hanging up on sites contain CodeMirror ([#62](https://github.com/horihiro/TextBlurrer-ChromeExtension/issues/62))
- Chores
- Add documentation about blurring on Xterm.js

## [0.2.2](https://github.com/horihiro/TextBlurrer-ChromeExtension/releases/tag/0.2.2)

- Bug fixes
- Improve performance ([#52](https://github.com/horihiro/TextBlurrer-ChromeExtension/issues/52)
- Improve performance ([#52](https://github.com/horihiro/TextBlurrer-ChromeExtension/issues/52))
- Fix adding exclusion URL patterns list

## [0.2.1](https://github.com/horihiro/TextBlurrer-ChromeExtension/releases/tag/0.2.1)

- Bug fixes
- Improve performance ([#48](https://github.com/horihiro/TextBlurrer-ChromeExtension/issues/48)
- Improve performance ([#48](https://github.com/horihiro/TextBlurrer-ChromeExtension/issues/48))

## [0.2.0](https://github.com/horihiro/TextBlurrer-ChromeExtension/releases/tag/0.2.0)

Expand Down
2 changes: 1 addition & 1 deletion background/service-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ chrome.contextMenus.onClicked.addListener(async(info, tab) => {
(keywords.length === 1 && keywords[0] === '') && keywords.pop();
const addingKeyword = (await chrome.storage.local.get(['mode']))?.mode === 'regexp' ? escapeRegExp(info.selectionText) : info.selectionText;
!keywords.includes(addingKeyword) && keywords.push(addingKeyword);
await chrome.storage.local.set({ 'keywords': keywords.join('\n') });
await chrome.storage.local.set({ 'keywords': keywords.join('\n').replace(/\u00a0/g, ' ') });
chrome.runtime.sendMessage({ method: 'reload' });
}
});
62 changes: 39 additions & 23 deletions content/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@
const src = chrome.runtime.getURL('util/common.js');
const { escapeRegExp } = await import(src);
const w = window;
const exElmList = ['html', 'title', 'script', 'noscript', 'style', 'meta', 'link', 'head', 'textarea', '#comment'];
const inputs = [];
const observedNodes = [];

const SKIP_NODE_NAMES = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'HEAD', 'META', 'LINK', 'HTML', 'TEXTAREA', 'TITLE', '#comment'];
const BLOCK_ELEMENT_NAMES = [
'ADDRESS', 'ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'CANVAS', 'DD', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION',
'FIGURE', 'FOOTER', 'FORM', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', 'HR', 'LI', 'MAIN', 'NAV', 'NOSCRIPT',
'OL', 'P', 'PRE', 'SCRIPT', 'SECTION', 'TABLE', 'TFOOT', 'UL', 'VIDEO'
];
const CLASS_NAME_BLURRED = 'tb-blurred';
const CLASS_PREFIX_BLURRED_GROUP = 'tb-blurred-group-';
const CLASS_NAME_KEEP = 'tb-keep-this';
const ATTR_NAME_ORIGINAL_TITLE = 'data-tb-original-title';
const CLASS_NAME_MASK_CONTAINER = 'tb-mask-container';
const CLASS_NAME_TEXT_LAYER = 'tb-mask-text-layer';
const CLASS_NAME_CODEMIRROR_EDITOR = 'cm-editor';
const ID_INPUT_CLONE = 'tb-input-clone';
const ID_GLOBAL_STYLE = '__blurring-style';
const GLOBAL_STYLE = `.${CLASS_NAME_BLURRED} {
Expand Down Expand Up @@ -46,13 +55,28 @@
}
});

const getStateOfContentEditable = (element) => {
if (element.contentEditable && element.contentEditable !== 'inherit') return element.contentEditable;
return element.parentNode ? getStateOfContentEditable(element.parentNode) : '';
};
const inputs = [];
const shouldBeSkipped = (node) => {
if (node.nodeType !== 1) return shouldBeSkipped(node.parentNode);

if (isBlurred(node)) {
console.debug(`Skipped. Reason: Already blurred`);
return true;
}
if (SKIP_NODE_NAMES.includes(node.nodeName)) {
console.debug(`Skipped. Reason: The nodeName is ${node.nodeName}`);
return true;
}
if (!!node.closest(`.${CLASS_NAME_CODEMIRROR_EDITOR}`)) {
console.debug(`Skipped. Reason: CodeMirror`);
return true;
}
if (node.isContentEditable) {
console.debug(`Skipped. Reason: The node is contentEditable`);
return true;
}
return false;
}

const SKIP_NODE_NAMES = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'HEAD', 'META', 'LINK', 'HTML', '#comment'];
const getNextTextNode = (e, root) => {
if (!e) return null;
if (e.firstChild && !SKIP_NODE_NAMES.includes(e.nodeName)) return e.firstChild.nodeName === '#text' ? e.firstChild : getNextTextNode(e.firstChild, root);
Expand Down Expand Up @@ -85,14 +109,10 @@
.replace(/[\n\t]/g, ' ') // step.2&3
.replace(/ +/g, ' ') // step.4
.trim() // step.5
.replace(/\u00a0/g, ' ') // additional
: ''
}

const BLOCK_ELEMENT_NAMES = [
'ADDRESS', 'ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'CANVAS', 'DD', 'DIV', 'DL', 'DT', 'FIELDSET', 'FIGCAPTION',
'FIGURE', 'FOOTER', 'FORM', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', 'HR', 'LI', 'MAIN', 'NAV', 'NOSCRIPT',
'OL', 'P', 'PRE', 'SCRIPT', 'SECTION', 'TABLE', 'TFOOT', 'UL', 'VIDEO'
];
const blockContents = (node) => {
return Array.from(node.childNodes).reduce((lines, child) => {
if (SKIP_NODE_NAMES.includes(child.nodeName)) return lines;
Expand Down Expand Up @@ -127,14 +147,10 @@
}

const isBlurred = (node) => {
do {
if (node.classList?.contains(CLASS_NAME_BLURRED)) return true;
node = node.parentNode;
} while (node);
return false;
return !!(node.nodeType == 1 ? node : node.parentNode).closest(`.${CLASS_NAME_BLURRED}`)
}

const getElementsToBeBlurred = (pattern, target, options) => {
const blockAndBlur = (pattern, target, options) => {
let textNode = getNextTextNode(target, target), pos = 0;
if (!textNode) return;
let _startsFrom = 0;
Expand Down Expand Up @@ -212,8 +228,7 @@
const insertNodes = [];
const removeNodes = [];
if (!from.node.parentNode || !to.node.parentNode
|| exElmList.includes(from.node.parentNode.nodeName.toLowerCase()) || exElmList.includes(from.node.parentNode.nodeName.toLowerCase())
|| isBlurred(from.node.parentNode) || isBlurred(to.node.parentNode)) return;
|| shouldBeSkipped(from.node) || shouldBeSkipped(to.node)) return;

if (from.node == to.node) {
const computedStyle = getComputedStyle(from.node.parentNode);
Expand Down Expand Up @@ -299,7 +314,7 @@
});
}
}
getElementsToBeBlurred(pattern, target || document.body, options);
blockAndBlur(pattern, target || document.body, options);

const blurInShadowRoot = (target) => {
target.shadowRoot && blur(pattern, options, target.shadowRoot);
Expand Down Expand Up @@ -450,7 +465,6 @@
inputObj.masks[p].forEach(m => m.style.setProperty('display', ''));
}
}
const observedNodes = [];
const blur = (pattern, options, target) => {
const observed = target || document.body;
if (observedNodes.includes(observed)) return;
Expand Down Expand Up @@ -608,10 +622,12 @@
const blurTabTitleCore = (pattern, target) => {
const title = target.textContent;
let result = title.match(pattern);
let start = 0;
while (result) {
const mask = new Array(result[0].length).fill('*').join('');
target.textContent = target.textContent.replace(result[0], mask);
result = target.textContent.match(pattern);
start += result.index + mask.length;
result = target.textContent.slice(start).match(pattern);
if (!target.getAttribute(ATTR_NAME_ORIGINAL_TITLE)) {
target.setAttribute(ATTR_NAME_ORIGINAL_TITLE, title);
}
Expand Down
37 changes: 37 additions & 0 deletions docs/BLUR_ON_XTERMJS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# How to blur text on Xterm.js
[![](https://github.com/xtermjs/xterm.js/raw/master/logo-full.png)](https://xtermjs.org/)

Xterm.js is a front-end component that lets applications bring fully-featured terminals to their users in the browser[^1]

[^1]: https://github.com/xtermjs/xterm.js/blob/master/README.md

Xterm.js has some types of renderer as followings.
- WebGL
- Canvas
- DOM

From point of view of the rendering performance, WebGL renderer is most recommended.
But Text Blurrer cannot blur text rendered by WebGL renderer and Canvas renderer because they draw text on HTML Canvas.

If you want to blur text on Xterm.js-base terminal, you should check which type of renderer is used to render text on the terminal and if the application using Xterm.js has a option to switch the renderer type of Xterm.js

> [!NOTE]
> Switching to DOM renderer for Xterm.js might cause performance issue of the terminal rendering.
> [!NOTE]
> DOM renderer seems to renders one line in the terminal as one `div` element.
> So when long text is splitted to two lines because of the terminal width, making complicated regular expression is needed in order to blur the text as one keyword.
## GitHub Codespaces
The terminal on GitHub Codespaces is based on Xterm.js.

Though the default renderer is WebGL renderer, it has a option about the terminal rendering.
By setting `terminal.integrated.gpuAcceleration` to `off`, DOM renderer can be enabled and text on the terminal can be blurred.
![image](https://github.com/horihiro/TextBlurrer-ChromeExtension/assets/4566555/3165d94c-38ac-48e9-b4db-6bad845f153b)

Example: realtime blurring output of `az account show` and `az sp create-for-rbac`

https://github.com/horihiro/TextBlurrer-ChromeExtension/assets/4566555/06264b16-cca3-4350-9680-25c556ced988

## Azure Cloud Shell
It seem that there is no option to switch rendering option, so it's difficult to blur text on Azure Cloud Shell currently.
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"manifest_version": 3,
"name": "Text Blurrer",
"version": "0.2.2",
"version_name": "0.2.2",
"version": "0.2.3",
"version_name": "0.2.3",
"description": "Blurring sensitive specified text/keyword.",
"permissions": [
"storage",
Expand Down
2 changes: 1 addition & 1 deletion popup/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ textarea#${e.target.id} {
applyButton.addEventListener('click', async (e) => {
await chrome.storage.local.set({
'status': !statusCheckbox.checked ? 'disabled' : '',
'keywords': patternInput.value,
'keywords': patternInput.value.replace(/\u00a0/g, ' '),
'exclusionUrls': exclusionInput.value,
'mode': regexpCheckbox.checked ? 'regexp' : 'text',
'matchCase': caseCheckbox.checked,
Expand Down

0 comments on commit f90997e

Please sign in to comment.