mirror of
https://github.com/anticensority/runet-censorship-bypass.git
synced 2024-11-24 02:13:43 +03:00
Handle TUNN CONN FAILED, sanitize optioins page url params, fix #50
This commit is contained in:
parent
1eb005f085
commit
719d6eac9c
File diff suppressed because it is too large
Load Diff
|
@ -17,12 +17,15 @@ export default function getApp(theState) {
|
|||
constructor(props) {
|
||||
|
||||
super(props);
|
||||
const hash = window.location.hash.substr(1);
|
||||
const hashParams = new URLSearchParams(hash);
|
||||
|
||||
const sanitizedUrl = theState.flags.ifOpenedUnsafely ? { hash: '', search: '' } : window.location;
|
||||
const hashParams = new URLSearchParams(sanitizedUrl.hash.substr(1));
|
||||
const searchParams = new URLSearchParams(sanitizedUrl.search.substr(1));
|
||||
this.state = {
|
||||
status: 'Загрузка...',
|
||||
ifInputsDisabled: false,
|
||||
hashParams: hashParams,
|
||||
hashParams,
|
||||
searchParams,
|
||||
};
|
||||
|
||||
this.setStatusTo = this.setStatusTo.bind(this);
|
||||
|
@ -62,9 +65,9 @@ export default function getApp(theState) {
|
|||
const uiComEtag = 'ui-last-comments-etag';
|
||||
const uiLastNewsArr = 'ui-last-news-arr';
|
||||
|
||||
const statusFromHash = this.state.hashParams.get('status');
|
||||
if (statusFromHash) {
|
||||
return this.setStatusTo(statusFromHash);
|
||||
const statusFromUrl = this.state.searchParams.get('status');
|
||||
if (statusFromUrl) {
|
||||
return this.setStatusTo(statusFromUrl);
|
||||
}
|
||||
|
||||
const comDate = localStorage[uiComDate];
|
||||
|
|
|
@ -17,24 +17,22 @@ export default function getFooter() {
|
|||
|
||||
`;
|
||||
|
||||
return function (props) {
|
||||
return (props) => (
|
||||
<div class="horPadded">
|
||||
<section class={scopedCss.statusRow}>
|
||||
<div class={scopedCss.status} style="will-change: contents">
|
||||
{typeof(props.status) === 'string' ? <div dangerouslySetInnerHTML={{ __html: props.status }}></div> : props.status}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
return (
|
||||
<div class="horPadded">
|
||||
<section class={scopedCss.statusRow}>
|
||||
<div clss={scopedCss.status} style="will-change: contents">{props.status}</div>
|
||||
</section>
|
||||
|
||||
<footer class={scopedCss.controlRow + ' horFlex nowrap'}>
|
||||
<input type="button" value={chrome.i18n.getMessage('Finish')} disabled={props.ifInputsDisabled} onClick={() => window.close()} />
|
||||
<a href="https://rebrand.ly/ac-donate">{chrome.i18n.getMessage('Donate')}</a>
|
||||
<a data-in-bg="false" href="../troubleshoot/index.html">
|
||||
{chrome.i18n.getMessage('ProblemsQ')}
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
<footer class={scopedCss.controlRow + ' horFlex nowrap'}>
|
||||
<input type="button" value={chrome.i18n.getMessage('Finish')} disabled={props.ifInputsDisabled} onClick={() => window.close()} />
|
||||
<a href="https://rebrand.ly/ac-donate">{chrome.i18n.getMessage('Donate')}</a>
|
||||
<a data-in-bg="false" href="../troubleshoot/index.html">
|
||||
{chrome.i18n.getMessage('ProblemsQ')}
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
|
||||
};
|
||||
|
|
|
@ -9,7 +9,13 @@ import getApp from './components/App';
|
|||
chrome.runtime.getBackgroundPage( (bgWindow) =>
|
||||
bgWindow.apis.errorHandlers.installListenersOn(
|
||||
window, 'PUP', async() => {
|
||||
|
||||
/*
|
||||
`Extension context invalidated` error is thrown if `window.closed` is true and call to
|
||||
`window.chrome.i18n` or other `window.chrome` api happens. Use bgWindow.chrome instead.
|
||||
Use winChrome for tab-related calls like winChrome.tabs.getCurrent.
|
||||
*/
|
||||
window.winChrome = window.chrome;
|
||||
window.chrome = bgWindow.chrome;
|
||||
let theState;
|
||||
{
|
||||
const apis = bgWindow.apis;
|
||||
|
@ -29,15 +35,23 @@ chrome.runtime.getBackgroundPage( (bgWindow) =>
|
|||
// IF INSIDE OPTIONS TAB
|
||||
|
||||
const currentTab = await new Promise(
|
||||
(resolve) => chrome.tabs.query(
|
||||
(resolve) => winChrome.tabs.query(
|
||||
{active: true, currentWindow: true},
|
||||
([tab]) => resolve(tab)
|
||||
([tab]) => resolve(tab),
|
||||
)
|
||||
);
|
||||
|
||||
theState.flags.ifInsideOptionsPage = !currentTab || currentTab.url.startsWith('chrome://extensions/?options=') || currentTab.url.startsWith('about:addons');
|
||||
theState.currentTab = currentTab;
|
||||
|
||||
// If opened not via popup and not via options modal.
|
||||
// E.g., if opened via copy-pasting an URL into the address bar from somewhere.
|
||||
// If browser is not Chrome (Opera, e.g.) then options page may be opened in a separate tab
|
||||
// and then you will get a false positive.
|
||||
theState.flags.ifOpenedUnsafely = Boolean(await new Promise(
|
||||
(resolve) => winChrome.tabs.getCurrent(resolve),
|
||||
));
|
||||
|
||||
// STATE DEFINED, COMPOSE.
|
||||
|
||||
appendGlobalCss(document, theState);
|
||||
|
|
|
@ -2,7 +2,88 @@
|
|||
|
||||
{
|
||||
|
||||
chrome.webNavigation.onErrorOccurred.addListener((details) => {
|
||||
const proxySideErrors = [
|
||||
'net::ERR_TUNNEL_CONNECTION_FAILED',
|
||||
];
|
||||
|
||||
const urlToA = (url) => new URL(url).host.link(
|
||||
encodeURIComponent(url),
|
||||
);
|
||||
|
||||
const isProxyErrorHandledAsync = async (details) => {
|
||||
|
||||
if (!proxySideErrors.includes(details.error) || details.type === 'main_frame') {
|
||||
// Main frame websocket errors are followed by webnavigation errors
|
||||
// which chrome-internals code resets the state of the popup.
|
||||
return;
|
||||
}
|
||||
let fromPageHref = '';
|
||||
let fromPageHtml = '';
|
||||
let youMayReportHtml = '';
|
||||
const initiator = details.initiator !== 'null' && details.initiator;
|
||||
try {
|
||||
if (initiator) {
|
||||
fromPageHref = new URL(initiator).href; // Sanitize: only urls, not other stuff.
|
||||
fromPageHtml = ` со страницы ${urlToA(fromPageHref)}`;
|
||||
}
|
||||
youMayReportHtml = ` Вы можете <b>${'сообщить об ошибке'.link(
|
||||
encodeURIComponent(
|
||||
'/pages/report-proxy-error/index.html?' +
|
||||
new URLSearchParams({
|
||||
fromPageHref,
|
||||
requestFailedTo: new URL(details.url).href,
|
||||
}),
|
||||
),
|
||||
)}</b> администратору прокси.`;
|
||||
} catch(e) {
|
||||
/* Suppress for malformed urls. */
|
||||
console.log('Error handling malformed URLs:', details);
|
||||
}
|
||||
|
||||
const tabId = details.tabId;
|
||||
const popupPrefix = chrome.runtime.getURL(`/pages/options/index.html?status=<span style="color: red">🔥 Прокси-сервер отказался обслуживать запрос к `);
|
||||
const oldPopup = await new Promise((resolve) => chrome.browserAction.getPopup({ tabId }, resolve));
|
||||
if (decodeURIComponent(oldPopup).startsWith(popupPrefix)) {
|
||||
return true;
|
||||
}
|
||||
const popup = `${popupPrefix}${urlToA(details.url)}${fromPageHtml}</span>. Это могло быть намеренно или по ошибке.${youMayReportHtml}#tab=exceptions`;
|
||||
|
||||
chrome.browserAction.setPopup({
|
||||
tabId,
|
||||
popup,
|
||||
});
|
||||
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
tabId,
|
||||
color: 'red',
|
||||
});
|
||||
chrome.browserAction.setBadgeText({
|
||||
tabId,
|
||||
text: '❗',
|
||||
});
|
||||
let limit = 5;
|
||||
let ifOnTurn = true;
|
||||
let ifError = false;
|
||||
const flip = () => {
|
||||
|
||||
if (!ifOnTurn && !--limit || ifError) {
|
||||
clearInterval(timer);
|
||||
return;
|
||||
}
|
||||
chrome.browserAction.setBadgeText({
|
||||
tabId,
|
||||
text: ifOnTurn ? '❗' : '',
|
||||
}, () => {
|
||||
ifError = chrome.runtime.lastError;
|
||||
});
|
||||
ifOnTurn = !ifOnTurn;
|
||||
};
|
||||
flip();
|
||||
const timer = setInterval(flip, 500);
|
||||
return true;
|
||||
};
|
||||
|
||||
chrome.webNavigation.onErrorOccurred.addListener(async (details) => {
|
||||
|
||||
const tabId = details.tabId;
|
||||
if ( !(details.frameId === 0 && tabId >= 0) ||
|
||||
|
@ -12,13 +93,16 @@
|
|||
].includes(details.error) ) {
|
||||
return;
|
||||
}
|
||||
if (await isProxyErrorHandledAsync(details)) {
|
||||
return;
|
||||
}
|
||||
|
||||
chrome.browserAction.setPopup({
|
||||
tabId,
|
||||
popup: './pages/options/index.html#tab=exceptions&status=Правый клик по иконке — меню инструментов!',
|
||||
popup: './pages/options/index.html?status=Правый клик по иконке — меню инструментов!#tab=exceptions',
|
||||
});
|
||||
|
||||
window.chrome.browserAction.setBadgeBackgroundColor({
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
tabId,
|
||||
color: '#4285f4',
|
||||
});
|
||||
|
@ -29,4 +113,9 @@
|
|||
|
||||
});
|
||||
|
||||
chrome.webRequest.onErrorOccurred.addListener(
|
||||
isProxyErrorHandledAsync,
|
||||
{urls: ['<all_urls>']},
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
const setRedBadge = (opts) => {
|
||||
|
||||
window.chrome.browserAction.setBadgeBackgroundColor({
|
||||
chrome.browserAction.setBadgeBackgroundColor({
|
||||
color: '#db4b2f',
|
||||
});
|
||||
chrome.browserAction.setBadgeText(opts);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Сообщить об ошибке прокси-сервера</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
:root {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Сообщить об ошибке прокси-сервера</h1>
|
||||
Перешлите администратору вашего прокси следующее:
|
||||
<fieldset>
|
||||
<pre id="errorInfo"></pre>
|
||||
</fieldset>
|
||||
Вот известные нам электронные адреса для популярных прокси-серверов (кликните по email для открытия шаблона письма):
|
||||
<ol>
|
||||
<li>
|
||||
Только если вы используете <a
|
||||
href="https://antizapret.prostovpn.org">Антизапрет</a>:
|
||||
<a
|
||||
href="mailto:antizapret@prostovpn.org">antizapret@prostovpn.org</a>.
|
||||
</li>
|
||||
</ol>
|
||||
<script src="./index.js"></script>
|
||||
<script src="../lib/keep-links-clickable.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
'use strict';
|
||||
|
||||
chrome.runtime.getBackgroundPage( (bgWindow) =>
|
||||
bgWindow.apis.errorHandlers.installListenersOn(
|
||||
window, 'PRERR', () => {
|
||||
|
||||
const params = new URLSearchParams(location.search.substr(1));
|
||||
const requestFailedTo = params.get('requestFailedTo');
|
||||
const fromPageHref = params.get('fromPageHref') || requestFailedTo;
|
||||
|
||||
const acr = bgWindow.apis.antiCensorRu;
|
||||
const pacKey = acr.getCurrentPacProviderKey();
|
||||
const pacModTime = acr.getLastModifiedForKey(pacKey);
|
||||
|
||||
const errorReport = `
|
||||
Your proxy blocked the following request:
|
||||
* Request was from page: ${fromPageHref}
|
||||
* To address: ${requestFailedTo}
|
||||
* Used PAC-script: ${pacKey}
|
||||
* Its Last-Modified HTTP-header: ${pacModTime}
|
||||
I think it's a mistake! Could you, please, take action to fix it.
|
||||
Thank you!
|
||||
|
||||
Ваш прокси-сервер заблокировал следующий запрос:
|
||||
* Запрос был со страницы: ${fromPageHref}
|
||||
* Адрес запроса: ${requestFailedTo}
|
||||
* Мой PAC-скрипт: ${pacKey}
|
||||
* Его HTTP-заголовок Last-Modified: ${pacModTime}
|
||||
Я думаю, это произошло по ошибке! Пожалуйста, примите действия для её исправления.
|
||||
Спасибо!
|
||||
`.trim();
|
||||
errorInfo.innerText = errorReport;
|
||||
document.querySelectorAll('a[href^="mailto:"]').forEach((a) => {
|
||||
|
||||
a.href = `${a.href}?subject=${encodeURIComponent(new URL(requestFailedTo).hostname)} TUNNEL_CONNECTION_FAILED&body=${encodeURIComponent(errorReport)}`;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
Loading…
Reference in New Issue
Block a user