From f0d69966ed9c3130759587413df4f06a4fca0a24 Mon Sep 17 00:00:00 2001 From: z0ccc Date: Fri, 28 Oct 2022 17:01:46 -0400 Subject: [PATCH] v3.4.7 --- modules/ext/package.json | 4 +- modules/ext/public/manifest/base.json | 4 +- modules/ext/src/plugins/proxy/pac.js | 20 +++- .../ext/src/plugins/proxy/shouldNotProxy.js | 12 ++- .../session/getSessionAndCheckStatus.js | 8 +- modules/ext/src/tests/setup.js | 2 +- modules/ext/src/utils/constants.js | 2 +- .../ext/src/utils/createCruiseControlList.js | 10 +- modules/ext/src/utils/public-ip.js | 21 +++-- .../src/views/Main/ProxyControls/Browser.js | 1 + .../src/views/Main/ProxyControls/IPAddress.js | 1 + .../src/views/PreferencesConnection/index.js | 2 +- .../ext/src/views/PreferencesPrivacy/index.js | 2 +- modules/ws-api-client/src/api/config.ts | 2 + modules/ws-api-client/src/api/http.ts | 17 ++++ modules/ws-api-client/src/api/sendRequest.ts | 93 ++++++++++++++----- 16 files changed, 146 insertions(+), 55 deletions(-) diff --git a/modules/ext/package.json b/modules/ext/package.json index 65b6827..2082358 100644 --- a/modules/ext/package.json +++ b/modules/ext/package.json @@ -1,6 +1,6 @@ { "name": "ext", - "version": "3.4.3", + "version": "3.4.7", "private": true, "dependencies": { "@babel/plugin-proposal-export-default-from": "~7.8.3", @@ -134,7 +134,7 @@ "web-ext": "~4.0.0", "webpack-dev-server": "^3.11.0" }, - "uBlockVersion": "ws-v1.42.4", + "uBlockVersion": "ws-v1.43.0", "main": "index.js", "license": "MIT" } diff --git a/modules/ext/public/manifest/base.json b/modules/ext/public/manifest/base.json index 09a173e..f2c71c9 100644 --- a/modules/ext/public/manifest/base.json +++ b/modules/ext/public/manifest/base.json @@ -2,9 +2,9 @@ "manifest_version": 2, "name": "Windscribe - Free Proxy and Ad Blocker", "short_name": "Windscribe", - "version": "3.4.3", + "version": "3.4.7", "description": "Windscribe helps you mask your physical location, circumvent censorship, and block ads and trackers on websites you use every day", - "content_security_policy": "script-src 'self'; object-src 'self';", + "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self';", "default_locale": "en", "browser_action": { "default_popup": "popup.html", diff --git a/modules/ext/src/plugins/proxy/pac.js b/modules/ext/src/plugins/proxy/pac.js index d9fafa0..10e1db7 100644 --- a/modules/ext/src/plugins/proxy/pac.js +++ b/modules/ext/src/plugins/proxy/pac.js @@ -1,13 +1,15 @@ // TODO: this file is getting minified in the build and breaking the pacfile // import shouldNotProxy from 'plugins/proxy/shouldNotProxy' import { stringify } from 'utils/createCruiseControlList' +import api from 'api' +import { store } from 'state' // get array of hostnames if exists (used for fallbacks) -const getParsedHostnamesString = hostnames => { +const getParsedHostnamesString = (hostnames, proxyPort) => { if (hostnames?.length > 0) { return hostnames.reduce((acc, hostname) => { //convert each into proxy list format - acc += `HTTPS ${hostname}:443;` + acc += `HTTPS ${hostname}:${proxyPort};` return acc }, '') } else { @@ -21,6 +23,9 @@ const createFindProxyForURLFunction = ({ cruiseControlList, whitelist = [], }) => { + const { workingApi } = api.getConfig() + const proxyPort = store.getState().proxyPort + const pac = ` function FindProxyForURL (url, host) { function shouldNotProxy(url, host, userWhitelist) { @@ -30,7 +35,14 @@ const createFindProxyForURLFunction = ({ '*://api.windscribe.com/*', '*://assets.windscribe.com/*', '*://*.staticnetcontent.com/*', - '*://*.totallyacdn.com/*', + '*://api.totallyacdn.com/*', + '*://assets.totallyacdn.com/*', + ${ + workingApi !== '.windscribe.com' + ? `'*://api${workingApi}/*', + '*://assets${workingApi}/*',` + : '' + } 'https://windscribe.com/installed/*', ].concat(userWhitelist) @@ -48,7 +60,7 @@ const createFindProxyForURLFunction = ({ return 'DIRECT' } ${cruiseControlList ? stringify(cruiseControlList) : ''} - return '${getParsedHostnamesString(hostnames)}' + return '${getParsedHostnamesString(hostnames, proxyPort)}' } ` return pac diff --git a/modules/ext/src/plugins/proxy/shouldNotProxy.js b/modules/ext/src/plugins/proxy/shouldNotProxy.js index b84a43a..b69d69d 100644 --- a/modules/ext/src/plugins/proxy/shouldNotProxy.js +++ b/modules/ext/src/plugins/proxy/shouldNotProxy.js @@ -1,3 +1,5 @@ +import api from 'api' + // These functions exist in the pac sandbox, but not in the typical browser env export const isPlainHostName = host => host.indexOf('.') === -1 @@ -60,17 +62,25 @@ export function shExpMatch(url, pattern) { */ // if this returns true then proxy should go DIRECT + export default function shouldNotProxy(url, host, userWhitelist) { + const { workingApi } = api.getConfig() + const lanIps = /(^(127|10)\.\d{1,3}\.\d{1,3}\.\d{1,3}$)|(^192\.168\.\d{1,3}\.\d{1,3}$)|(^172\.1[6-9]\.\d{1,3}\.\d{1,3}$)|(^172\.2[0-9]\.\d{1,3}\.\d{1,3}$)|(^172\.3[0-1]\.\d{1,3}\.\d{1,3}$)/ const whitelist = [ '*://api.windscribe.com/*', '*://assets.windscribe.com/*', '*://*.staticnetcontent.com/*', - '*://*.totallyacdn.com/*', + '*://api.totallyacdn.com/*', + '*://assets.totallyacdn.com/*', 'https://windscribe.com/installed/*', ].concat(userWhitelist) + if (workingApi !== '.windscribe.com') { + whitelist.push(`*://api${workingApi}/*`, `*://assets${workingApi}/*`) + } + return [ isPlainHostName(host), // if it is NOT an allowed protocol then go direct diff --git a/modules/ext/src/plugins/session/getSessionAndCheckStatus.js b/modules/ext/src/plugins/session/getSessionAndCheckStatus.js index d786327..45ab678 100644 --- a/modules/ext/src/plugins/session/getSessionAndCheckStatus.js +++ b/modules/ext/src/plugins/session/getSessionAndCheckStatus.js @@ -162,13 +162,7 @@ export default actions => [ message: `get latest session info failed: ${err.message}`, }) // if session if invalid, logout - // 501 & 502 are validation errors - if ( - err.code === SESSION_ERRORS.SESSION_INVALID || - err.code === SESSION_ERRORS.NO_AUTH_HASH || - err.code === 501 || - err.code === 502 - ) { + if (err.code === SESSION_ERRORS.SESSION_INVALID) { // this error will appear when you reach login page dispatch( actions.session.assign({ diff --git a/modules/ext/src/tests/setup.js b/modules/ext/src/tests/setup.js index 161aff8..d6bf469 100644 --- a/modules/ext/src/tests/setup.js +++ b/modules/ext/src/tests/setup.js @@ -11,7 +11,7 @@ import { store, actions } from 'state' export default async () => { window.ipAddress = await checkIp() - window.ublockNetWhitelist = µBlock.netWhitelist + // window.ublockNetWhitelist = µBlock.netWhitelist window.checkIp = checkIp window.constants = constants window.sleep = sleep diff --git a/modules/ext/src/utils/constants.js b/modules/ext/src/utils/constants.js index 2809eb6..ab16c67 100644 --- a/modules/ext/src/utils/constants.js +++ b/modules/ext/src/utils/constants.js @@ -206,7 +206,7 @@ export const AUTH_RESET_MIN_INTERVAL = export const RENDER_TIMEOUT = process.env.WEB_EXT_RENDER_TIMEOUT || 5000 export const PROXY_PORT = - process.env.WEB_EXT_PROXY_PORT || IS_FIREFOX ? '80' : '443' + process.env.WEB_EXT_PROXY_PORT || IS_FIREFOX ? '9443' : '443' export const API_CALL_MIN_INTERVAL = process.env.WEB_EXT_API_CALL_MIN_INTERVAL || 1000 diff --git a/modules/ext/src/utils/createCruiseControlList.js b/modules/ext/src/utils/createCruiseControlList.js index edc0c42..84bb882 100644 --- a/modules/ext/src/utils/createCruiseControlList.js +++ b/modules/ext/src/utils/createCruiseControlList.js @@ -1,5 +1,6 @@ import { flatten } from 'lodash' import pickHosts from './pickHosts' +import { store } from 'state' export default ({ serverlist, userPremiumStatus, cruiseControlDomains }) => { // we only care about servers we can actually access @@ -25,14 +26,17 @@ export default ({ serverlist, userPremiumStatus, cruiseControlDomains }) => { })) } -export const stringify = cruiseControlList => - cruiseControlList +export const stringify = cruiseControlList => { + const proxyPort = store.getState().proxyPort + + return cruiseControlList .map( loc => `if ([${flatten( loc.domains.map(domain => [`'*://${domain}/*'`, `'*.${domain}/*'`]), )}].some(d => shExpMatch(url, d))) { - return '${loc.hosts.map(x => `HTTPS ${x}:443`).join('; ')}' + return '${loc.hosts.map(x => `HTTPS ${x}:${proxyPort}`).join('; ')}' }`, ) .join('\n') +} diff --git a/modules/ext/src/utils/public-ip.js b/modules/ext/src/utils/public-ip.js index dbe1b54..e235b4c 100644 --- a/modules/ext/src/utils/public-ip.js +++ b/modules/ext/src/utils/public-ip.js @@ -1,11 +1,16 @@ +import api from 'api' + export default async () => { - const controller = new AbortController() - setTimeout(() => controller.abort(), 3000) + const { workingApi } = api.getConfig() + if (workingApi) { + const controller = new AbortController() + setTimeout(() => controller.abort(), 3000) - const response = await fetch('https://checkipv4.windscribe.com', { - signal: controller.signal, - }) - .then(r => r.text()) - .catch(() => '---.---.---.---') - return response + return await fetch(`https://checkip${workingApi}`, { + signal: controller.signal, + }) + .then(r => r.text()) + .catch(() => '---.---.---.---') + } + return '---.---.---.---' } diff --git a/modules/ext/src/views/Main/ProxyControls/Browser.js b/modules/ext/src/views/Main/ProxyControls/Browser.js index bf30653..861594a 100644 --- a/modules/ext/src/views/Main/ProxyControls/Browser.js +++ b/modules/ext/src/views/Main/ProxyControls/Browser.js @@ -67,6 +67,7 @@ export default memo(() => { css={css` align-items: center; justify-content: start; + width: 150px; `} > diff --git a/modules/ext/src/views/Main/ProxyControls/IPAddress.js b/modules/ext/src/views/Main/ProxyControls/IPAddress.js index a15f084..e89bea1 100644 --- a/modules/ext/src/views/Main/ProxyControls/IPAddress.js +++ b/modules/ext/src/views/Main/ProxyControls/IPAddress.js @@ -121,6 +121,7 @@ export default memo(({ showIpCopiedAlert, setIpCopiedAlert }) => { text-overflow: ellipsis; cursor: ${status === 'error' ? 'default' : 'pointer'}; ${isIpBlurred && `text-shadow: 0px 0px 6px rgba(255,255,255,0.5);`} + width: 140px; `} fontSize={0} notranslate="true" diff --git a/modules/ext/src/views/PreferencesConnection/index.js b/modules/ext/src/views/PreferencesConnection/index.js index 980ab1f..681ddd8 100644 --- a/modules/ext/src/views/PreferencesConnection/index.js +++ b/modules/ext/src/views/PreferencesConnection/index.js @@ -69,7 +69,7 @@ export default () => { diff --git a/modules/ext/src/views/PreferencesPrivacy/index.js b/modules/ext/src/views/PreferencesPrivacy/index.js index 35eddd9..b4af481 100644 --- a/modules/ext/src/views/PreferencesPrivacy/index.js +++ b/modules/ext/src/views/PreferencesPrivacy/index.js @@ -162,7 +162,7 @@ export default () => { subHeading={ 'Limits WebRTC requests to prevent leaks. This may break some applications.' } - path={'features/timezone-spoofing'} + path={'features/webrtc-slayer'} Icon={WebRTCIcon} > { + const res = await fetch( + 'https://1.1.1.1/dns-query?name=dynamic-api-host.windscribe.com&type=TXT', + { + method: 'GET', + headers: { + Accept: 'application/dns-json', + }, + }, + ) + const data = await res.json() + + return data.Answer[0].data.slice(1, -1) +} + +const prepareValidUrl = async ({ + apiDomain, url, assets = false, - useBackup = false, }: PrepareValidUrlArgs) => { - const { assetsUrl, apiUrl, backupApiUrl, backupAssetsUrl } = getConfig() - const urlValidator = new RegExp(/^http|ftp|file:\/\//gim) // If it's a full url send use it as is if (urlValidator.test(url)) { @@ -22,11 +37,7 @@ const prepareValidUrl = ({ } let baseUrl - if (useBackup) { - baseUrl = assets ? backupAssetsUrl : backupApiUrl - } else { - baseUrl = assets ? assetsUrl : apiUrl - } + baseUrl = assets ? `https://assets${apiDomain}` : `https://api${apiDomain}` // If it's a base endpoint without a / starting add it if (!urlValidator.test(url) && !url.startsWith('/')) { @@ -37,8 +48,6 @@ const prepareValidUrl = ({ } } -const _fetch = typeof fetch === 'function' ? fetch : require('node-fetch') - const sendRequest = async ({ endpoint, debugOpts = {}, @@ -48,7 +57,7 @@ const sendRequest = async ({ }: RequestArgs): Promise => { const RATE_LIMIT_ERROR_CODE = 7331 /* Sets the url, if there's params it'll construct and append the params to the url */ - const defaultParams = { ...opts.params, platform: getConfig().platform } + const params = { ...opts.params, platform: getConfig().platform } /* Sets up the config. if there's a key named method just pass the options object. @@ -56,17 +65,22 @@ const sendRequest = async ({ */ const config = opts.method ? opts : { ...opts, method } - const send = async (useBackup = false) => { + const send = async (apiDomain, useBackup = false) => { const { lastCallTimeStamps = {}, apiCallMinInterval } = getConfig() - const params = - useBackup && endpoint.includes('ExtBlocklists') // Only need to add `domain` on ExtBlocklists - ? { ...defaultParams, domain: 'totallyacdn.com' } - : defaultParams - const apiUrl = prepareValidUrl({ url: endpoint, assets, useBackup }) + const apiUrl = await prepareValidUrl({ + apiDomain, + url: endpoint, + assets, + }) + + if (!apiUrl) return null + const url = apiUrl + `?${qs.stringify(params)}` + const debugUrl = apiUrl global.url = debugUrl + const timeToNextCall = Number(apiCallMinInterval) - (Date.now() - lastCallTimeStamps[endpoint] ?? 0) @@ -86,14 +100,21 @@ const sendRequest = async ({ const controller = new AbortController() setTimeout(() => controller.abort(), 3000) - let params: RequestInit = { + const request: RequestInit = { headers: config.headers as HeadersInit, method: config.method, body: config.body, signal: controller.signal, } - const response = await fetch(url, params) + const response = await fetch(url, request) + + let { workingApi } = getConfig() + if (!workingApi) { + setConfig({ + workingApi: apiDomain, + }) + } if (response.status === 404) { throw { @@ -106,6 +127,7 @@ const sendRequest = async ({ data: { debugUrl, debugOpts }, } as ApiException } + return response } catch (e) { console.error(e) @@ -118,19 +140,42 @@ const sendRequest = async ({ } } + const { apiUrl, backupApiUrl, workingApi } = getConfig() + + const apiDomain = apiUrl.split('api')[1] + const backupApiDomain = backupApiUrl.split('api')[1] + /* Make the request */ try { - const resp = await send() + const resp = await send(workingApi || apiDomain) return resp } catch (e) { console.error(e.message) let resp if (e.code === RATE_LIMIT_ERROR_CODE) { await new Promise(resolve => setTimeout(resolve, e.data.timeToNextCall)) - resp = await send() + resp = await send(workingApi || apiDomain) } else { - // TODO: Figure out when to retry - resp = await send(true) + try { + setConfig({ + workingApi: null, + }) + resp = await send(backupApiDomain, true) + + return resp + } catch { + try { + setConfig({ + workingApi: null, + }) + const dohUrl = await fetchDoh() + resp = await send(`.${dohUrl}`, true) + + return resp + } catch { + return null + } + } } return resp }