mirror of
https://github.com/anticensority/runet-censorship-bypass.git
synced 2024-11-10 19:46:34 +03:00
Add js-logic to the popup's pacChooser form. Remove code related to CopyUnicodeUrls
This commit is contained in:
parent
bc75c74c8a
commit
0eb6194bc6
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "runet-censorship-bypass",
|
||||
"version": "0.2.0",
|
||||
"version": "0.0.2",
|
||||
"description": "",
|
||||
"homepage": "https://github.com/ilyaigpetrov/copy-unicode-urls#readme",
|
||||
"main": "index.js",
|
||||
|
@ -20,7 +20,6 @@
|
|||
},
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"punycode": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"merge": "^2.1.1",
|
||||
|
|
|
@ -3,12 +3,8 @@ import { versions, storage } from '../lib/index.mjs';
|
|||
globalThis.migrationPromise = new Promise(async (resolve) => {
|
||||
console.log('Checking for migrations...');
|
||||
const dflts = {
|
||||
options: [
|
||||
[ 'ifToDecode', true ],
|
||||
[ 'ifToDecodeMultipleTimes', false ],
|
||||
[ 'ifToEncodeUrlTerminators', true ],
|
||||
],
|
||||
donateUrl: 'https://rebrand.ly/ilya-donate',
|
||||
// TODO: Define defaults.
|
||||
options: {},
|
||||
};
|
||||
const ifEmpty = await storage.isEmptyAsync();
|
||||
if (ifEmpty) {
|
||||
|
@ -23,21 +19,20 @@ globalThis.migrationPromise = new Promise(async (resolve) => {
|
|||
console.log(`Current extension version is ${versions.current}.`);
|
||||
const oldVersion = await storage.getAsync('version');
|
||||
const ifNoNeedToMigrate = oldVersion === versions.current;
|
||||
if (ifNoNeedToMigrate) {http://я.рф/яhttp://я.рф/я
|
||||
if (ifNoNeedToMigrate) {
|
||||
console.log('No need for migration.');
|
||||
return resolve();
|
||||
}
|
||||
console.log(`Migrating to ${versions.current} from ${oldVersion || 'a very old version'}.`);
|
||||
switch(true) {
|
||||
case !oldVersion: {
|
||||
// Update from version <= 0.0.18.
|
||||
const ifSentence = await storage.getAsync('ifToEncodeSentenceTerminators');
|
||||
// Update from version <= 0.0.1.
|
||||
const ifSentence = await storage.getAsync('SOME_KEY');
|
||||
if (ifSentence !== undefined) {
|
||||
console.log('Migrating to 0.0.18.');
|
||||
console.log('Migrating to 0.0.1.');
|
||||
await storage.setAsync({
|
||||
ifToEncodeUrlTerminators: ifSentence,
|
||||
});
|
||||
await storage.removeAsync('ifToEncodeSentenceTerminators')
|
||||
}
|
||||
}; // Fallthrough.
|
||||
case versions.isLeq(oldVersion, '0.0.18'): {
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
import { toUnicode } from '../../node_modules/punycode/punycode.es6.js';
|
||||
import { copyToClipboardAsync } from '../lib/copy-to-clipboard.mjs';
|
||||
import { storage } from '../lib/index.mjs';
|
||||
|
||||
console.log('Main script starts...');
|
||||
|
||||
(async () => {
|
||||
const theState = await storage.getAsync();
|
||||
console.log('The state is:', theState);
|
||||
})();
|
||||
|
||||
/*
|
||||
const ID_TO_MENU_HANDLER = {};
|
||||
|
||||
const createMenuEntry = (id, type, title, handler, contexts, rest) => {
|
||||
|
@ -27,63 +33,6 @@ const copyUrlInstalledPromise = (async () => {
|
|||
console.log('Migration is finished.');
|
||||
|
||||
const options = await storage.getAsync('options');
|
||||
const getOpt = (key) => (options.find((el) => el[0] === key)[1]);
|
||||
console.log('Options are:', options);
|
||||
|
||||
const localizeUrl = (url) => {
|
||||
console.log('Localizing url:', url);
|
||||
let u;
|
||||
try {
|
||||
u = new URL(url);
|
||||
} catch {
|
||||
u = new URL(`http://${url}`);
|
||||
}
|
||||
let newHref = u.href;
|
||||
let oldHref;
|
||||
do {
|
||||
oldHref = newHref;
|
||||
newHref = decodeURI(
|
||||
newHref
|
||||
.replace(u.hostname, toUnicode(u.hostname))
|
||||
/*
|
||||
Don't decode `%25` to `%` because it causes errors while being put in GitHub URLs.
|
||||
Test case: https://github.com/ilyaigpetrov/copy-unicode-urls/wiki/Test-%25-and-%3F
|
||||
*/
|
||||
.replaceAll('%25', '%2525'),
|
||||
)
|
||||
// Encode whitespace.
|
||||
.replace(
|
||||
/\s/g,
|
||||
(_, index, wholeString) => encodeURIComponent(wholeString.charAt(index)),
|
||||
);
|
||||
} while (getOpt('ifToDecodeMultipleTimes') && oldHref !== newHref);
|
||||
console.log('Localized:', newHref);
|
||||
return newHref;
|
||||
};
|
||||
|
||||
const copyUrl = async (url) => {
|
||||
if (getOpt('ifToDecode')) {
|
||||
url = localizeUrl(url);
|
||||
}
|
||||
if (getOpt('ifToEncodeUrlTerminators')) {
|
||||
console.log('Encoding terminators...');
|
||||
/*
|
||||
Issue #7.
|
||||
Thunderbird sources:
|
||||
https://searchfox.org/comm-central/source/mozilla/netwerk/streamconv/converters/mozTXTToHTMLConv.cpp#281 (mozTXTToHTMLConv::FindURLEnd)
|
||||
These chars terminate the URL: ><"`}{)]`
|
||||
These sequence doesn't terminate the URL: //[ (e.g. http://[1080::...)
|
||||
These chars are not allowed at the end of the URL: .,;!?-:'
|
||||
I apply slightly more strict rules below.
|
||||
**/
|
||||
const toPercentCode = (char) => '%' + char.charCodeAt(0).toString(16).toUpperCase();
|
||||
url = url.replace(
|
||||
/(?:[<>{}()[\]"`']|[.,;:!?-]$)/g,
|
||||
(matchedChar, index, wholeString) => toPercentCode(matchedChar),
|
||||
);
|
||||
}
|
||||
copyToClipboardAsync(url);
|
||||
};
|
||||
|
||||
// CheckBoxes
|
||||
const capitalizeFirstLetter = (str) => str
|
||||
|
@ -137,12 +86,12 @@ const copyUrlInstalledPromise = (async () => {
|
|||
'copyHighlightLink', 'normal',
|
||||
chrome.i18n.getMessage('CopyUnicodeLinkToHighlight'),
|
||||
(info) => {
|
||||
copyUrl(`${info.pageUrl.replace(/#.*/g, '')}#:~:text=${info.selectionText}`);
|
||||
copyUrl(`${info.pageUrl.replace(/#.*\/g, '')}#:~:text=${info.selectionText}`);
|
||||
},
|
||||
['selection'],
|
||||
);
|
||||
|
||||
return copyUrl;
|
||||
return Promise.resolve();
|
||||
|
||||
})();
|
||||
|
||||
|
@ -162,5 +111,6 @@ chrome.action.onClicked.addListener(async ({ url: urlToBeCopied }) => {
|
|||
console.log('Main waits for listeners to be installed...');
|
||||
const copyUrl = await copyUrlInstalledPromise;
|
||||
console.log('Action clicked with url:', urlToBeCopied);
|
||||
copyUrl(urlToBeCopied);
|
||||
//copyUrl(urlToBeCopied);
|
||||
});
|
||||
*/
|
|
@ -1,5 +1,5 @@
|
|||
import "./00-start.mjs";
|
||||
import "./05-data-init-and-migrations.mjs";
|
||||
import "./10-main.mjs";
|
||||
import './00-start.mjs';
|
||||
import './05-data-init-and-migrations.mjs';
|
||||
import './10-main.mjs';
|
||||
|
||||
console.log('Background script finished loading.');
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
let IF_ALREADY_PROMISE; // A global promise to avoid concurrency issues.
|
||||
const OFFSCREEN_DOC_PATH = '/src/lib/offscreen-doc-for-copying.html';
|
||||
|
||||
export const copyToClipboardAsync = async (copyMe) => {
|
||||
console.log('Going to copy this url:', copyMe);
|
||||
try {
|
||||
console.log('Trying `navigator.clipboard`...');
|
||||
return await navigator.clipboard.writeText(copyMe);
|
||||
} catch(e) {
|
||||
console.log('Got error while copying attempt:', e);
|
||||
if (globalThis.document) {
|
||||
console.log('Trying `globalThis.document`...');
|
||||
const area = document.createElement('textarea');
|
||||
area.value = copyMe;
|
||||
document.body.appendChild(area);
|
||||
area.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(area);
|
||||
return;
|
||||
}
|
||||
console.log('Trying `chrome.offscreen`...');
|
||||
|
||||
async function setupOffscreenDocument(path) {
|
||||
// Check all windows controlled by the service worker to see if one
|
||||
// of them is the offscreen document with the given path
|
||||
const offscreenUrl = chrome.runtime.getURL(path);
|
||||
const existingContexts = await chrome.runtime.getContexts({
|
||||
contextTypes: ['OFFSCREEN_DOCUMENT'],
|
||||
documentUrls: [offscreenUrl],
|
||||
});
|
||||
console.log('Existing contexts:', existingContexts);
|
||||
|
||||
if (existingContexts.length > 0) {
|
||||
console.log('Offscreen document already exists.');
|
||||
return;
|
||||
}
|
||||
|
||||
// create offscreen document
|
||||
if (IF_ALREADY_PROMISE) {
|
||||
return IF_ALREADY_PROMISE;
|
||||
}
|
||||
console.log('Creating new offscreen document for:', path);
|
||||
IF_ALREADY_PROMISE = chrome.offscreen.createDocument({
|
||||
url: path,
|
||||
reasons: [chrome.offscreen.Reason.CLIPBOARD],
|
||||
justification: 'reason for needing the document',
|
||||
});
|
||||
await IF_ALREADY_PROMISE;
|
||||
console.log('New offscreen document created.');
|
||||
IF_ALREADY_PROMISE = null;
|
||||
}
|
||||
await setupOffscreenDocument(OFFSCREEN_DOC_PATH);
|
||||
// Now that we have an offscreen document, we can dispatch the
|
||||
// message.
|
||||
chrome.runtime.sendMessage({
|
||||
type: 'copy-data-to-clipboard',
|
||||
target: 'offscreen-doc',
|
||||
data: copyMe,
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<textarea id="text"></textarea>
|
||||
<script src="./offscreen-doc-for-copying.mjs" type="module"></script>
|
|
@ -1,74 +0,0 @@
|
|||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Once the message has been posted from the service worker, checks are made to
|
||||
// confirm the message type and target before proceeding. This is so that the
|
||||
// module can easily be adapted into existing workflows where secondary uses for
|
||||
// the document (or alternate offscreen documents) might be implemented.
|
||||
|
||||
// Registering this listener when the script is first executed ensures that the
|
||||
// offscreen document will be able to receive messages when the promise returned
|
||||
// by `offscreen.createDocument()` resolves.
|
||||
chrome.runtime.onMessage.addListener(handleMessages);
|
||||
|
||||
// This function performs basic filtering and error checking on messages before
|
||||
// dispatching the
|
||||
// message to a more specific message handler.
|
||||
async function handleMessages(message) {
|
||||
// Return early if this message isn't meant for the offscreen document.
|
||||
if (message.target !== 'offscreen-doc') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispatch the message to an appropriate handler.
|
||||
switch (message.type) {
|
||||
case 'copy-data-to-clipboard':
|
||||
handleClipboardWrite(message.data);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unexpected message type received: '${message.type}'.`);
|
||||
}
|
||||
}
|
||||
|
||||
// We use a <textarea> element for two main reasons:
|
||||
// 1. preserve the formatting of multiline text,
|
||||
// 2. select the node's content using this element's `.select()` method.
|
||||
const textEl = document.querySelector('#text');
|
||||
|
||||
// Use the offscreen document's `document` interface to write a new value to the
|
||||
// system clipboard.
|
||||
//
|
||||
// At the time this demo was created (Jan 2023) the `navigator.clipboard` API
|
||||
// requires that the window is focused, but offscreen documents cannot be
|
||||
// focused. As such, we have to fall back to `document.execCommand()`.
|
||||
async function handleClipboardWrite(data) {
|
||||
try {
|
||||
// Error if we received the wrong kind of data.
|
||||
if (typeof data !== 'string') {
|
||||
throw new TypeError(
|
||||
`Value provided must be a 'string', got '${typeof data}'.`
|
||||
);
|
||||
}
|
||||
|
||||
// `document.execCommand('copy')` works against the user's selection in a web
|
||||
// page. As such, we must insert the string we want to copy to the web page
|
||||
// and to select that content in the page before calling `execCommand()`.
|
||||
textEl.value = data;
|
||||
textEl.select();
|
||||
document.execCommand('copy');
|
||||
} finally {
|
||||
// Job's done! Close the offscreen document.
|
||||
window.close();
|
||||
}
|
||||
}
|
|
@ -40,11 +40,13 @@
|
|||
same even after invertion. Also a flash/blink of colors
|
||||
during invertion must be avoided.
|
||||
*/
|
||||
/*
|
||||
background-color: white; /* Not transparent. */
|
||||
color: black;
|
||||
/*color: black;
|
||||
/*
|
||||
border: 0 none white;
|
||||
outline: 0 none white;
|
||||
color-scheme: light;
|
||||
outline: 0 none white;*/
|
||||
/*color-scheme: light;
|
||||
/* COLOR INVERTION */
|
||||
filter: invert(0); /* TODO: temporary disabled. */
|
||||
}
|
||||
|
@ -79,8 +81,8 @@
|
|||
vertical-align: text-bottom;
|
||||
}
|
||||
input[type="url"] {
|
||||
border-width: 0 0 1px 0;
|
||||
border-color: crimson;
|
||||
/*border-width: 0 0 1px 0;
|
||||
border-color: crimson;*/
|
||||
flex-grow: 1;
|
||||
/*padding: 0 3px 0 3px;*/
|
||||
/*width: 100%;*/
|
||||
|
@ -88,6 +90,14 @@
|
|||
input[type="radio"], label {
|
||||
cursor: pointer;
|
||||
}
|
||||
#disabled:checked + label {
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.nowrap {
|
||||
/* Don't break sentences on spaces. */
|
||||
white-space: nowrap;
|
||||
}
|
||||
/*
|
||||
#own:checked + label:after {
|
||||
content: ":";
|
||||
|
@ -96,14 +106,17 @@
|
|||
#own ~ div {
|
||||
display: flex;
|
||||
}
|
||||
#disabled:checked + label {
|
||||
color: crimson;
|
||||
/*
|
||||
input#own ~ div:has(> input#customPacUrl):after {
|
||||
border: 5px solid lime;
|
||||
background-color: navy;
|
||||
content: "";
|
||||
}
|
||||
input#own ~ div:after:not(:empty) {
|
||||
border: 5px solid pink;
|
||||
}
|
||||
*/
|
||||
|
||||
div.nowrap {
|
||||
/* Don't break sentences on spaces. */
|
||||
white-space: nowrap;
|
||||
}
|
||||
.use-preferred-color-scheme {
|
||||
/*background-color: violet;
|
||||
color: darkred;*/
|
||||
|
@ -134,40 +147,53 @@
|
|||
bottom: 0;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
input:invalid {
|
||||
border: 5px solid red;
|
||||
}*/
|
||||
#customPacUrl:disabled {
|
||||
/*background-color: grey;*/
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="use-preferred-color-scheme">
|
||||
<!--img src="./gsbg.png" class="gsbg"-->
|
||||
<header>
|
||||
PAC-script:
|
||||
PAC-скрипт:
|
||||
</header>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
<input type="radio" value="antizapret" name="pacScript" id="antizapret">
|
||||
<label for="antizapret">Антизапрет</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="radio" value="anticensority" name="pacScript" id="anticensority">
|
||||
<label for="anticensority">Антицензорити</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="radio" value="own" name="pacScript" id="own">
|
||||
<label for="own">Свой:</label>
|
||||
<div>
|
||||
<input type="url" placeholder="https://example.com/proxy.pac">
|
||||
<button>Save</button>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<input type="radio" value="disabled" name="pacScript" id="disabled" checked>
|
||||
<label for="disabled">Отключить / сброс</label>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nowrap">
|
||||
<input type="checkbox" name="reset" id="reset" checked>
|
||||
<label for="reset">Сбрасывать перед переключением</label>
|
||||
</div>
|
||||
<form id="pacChooserForm">
|
||||
<ul>
|
||||
<li>
|
||||
<input type="radio" value="antizapret" name="pacScript" id="antizapret">
|
||||
<label for="antizapret">Антизапрет</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="radio" value="anticensority" name="pacScript" id="anticensority">
|
||||
<label for="anticensority">Антицензорити</label>
|
||||
</li>
|
||||
<li>
|
||||
<input type="radio" value="own" name="pacScript" id="own" disabled>
|
||||
<label for="own">Свой:</label>
|
||||
<div>
|
||||
<input id="customPacUrl" type="url" placeholder="https://example.com/proxy.pac"
|
||||
size="27"
|
||||
spellcheck="false" autocorrect="off" autocapitalize="off"
|
||||
disabled required
|
||||
>
|
||||
<button id="editPacUrlButton" title="Редактировать">🖉</button>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<input type="radio" value="disabled" name="pacScript" id="disabled" checked>
|
||||
<label for="disabled">Отключить / сброс</label>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="nowrap">
|
||||
<input type="checkbox" name="reset" id="reset" checked>
|
||||
<label for="reset">Сбрасывать перед переключением</label>
|
||||
</div>
|
||||
</form>
|
||||
</nav>
|
||||
<footer style="text-align: center">
|
||||
<a id="donate" target="_blank" data-localize="__MSG_Donate__"
|
||||
|
|
|
@ -1,3 +1,41 @@
|
|||
console.log('Options page is opening...');
|
||||
|
||||
pacChooserForm.addEventListener('change', function (event) {
|
||||
console.log('ON CHANGE:', event);
|
||||
pacChooserForm.reportValidity();
|
||||
});
|
||||
|
||||
pacChooserForm.addEventListener('formdata', (event) => {
|
||||
event.preventDefault();
|
||||
console.log('ON FORMDATA', event);
|
||||
return false; // Prevent default action.
|
||||
});
|
||||
|
||||
editPacUrlButton.onclick = function (event) {
|
||||
event.preventDefault();
|
||||
const lockUrl = () => { customPacUrl.disabled = true; };
|
||||
const unlockUrl = () => { customPacUrl.disabled = false; };
|
||||
const ifUrlLocked = customPacUrl.disabled;
|
||||
if (ifUrlLocked) {
|
||||
unlockUrl();
|
||||
return false;
|
||||
}
|
||||
const ifUrlValid = customPacUrl.checkValidity();
|
||||
if (ifUrlValid) {
|
||||
lockUrl();
|
||||
own.disabled = false;
|
||||
// TODO: Save to storage.
|
||||
return false;
|
||||
}
|
||||
// Empty or incorrect url.
|
||||
own.disabled = true; // `own.checked` doesn't matter here.
|
||||
const ifUrlEmpty = !customPacUrl.value;
|
||||
if (ifUrlEmpty) {
|
||||
lockUrl();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/*
|
||||
import { storage } from '../../lib/common-apis.mjs';
|
||||
|
||||
|
@ -18,6 +56,8 @@ options.forEach(([key, value], i) => {
|
|||
};
|
||||
});
|
||||
*/
|
||||
await chrome.storage.local.get('options');
|
||||
|
||||
const textElements = document.querySelectorAll('[data-localize]');
|
||||
textElements.forEach((e) => {
|
||||
const ref = e.dataset.localize;
|
||||
|
|
Loading…
Reference in New Issue
Block a user