background.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. (function() {
  2. var Log, OmegaTargetCurrent, Promise, actionForUrl, charCodeUnderscore, dispName, drawContext, drawError, drawIcon, encodeError, external, iconCache, isHidden, options, proxyImpl, refreshActivePageIfEnabled, state, storage, sync, syncStorage, tabs, timeout, unhandledPromises, unhandledPromisesId, unhandledPromisesNextId, _ref, _ref1, _writeLogToLocalStorage,
  3. __slice = [].slice,
  4. __hasProp = {}.hasOwnProperty;
  5. OmegaTargetCurrent = Object.create(OmegaTargetChromium);
  6. Promise = OmegaTargetCurrent.Promise;
  7. Promise.longStackTraces();
  8. OmegaTargetCurrent.Log = Object.create(OmegaTargetCurrent.Log);
  9. Log = OmegaTargetCurrent.Log;
  10. _writeLogToLocalStorage = function(content) {
  11. var _;
  12. try {
  13. return localStorage['log'] += content;
  14. } catch (_error) {
  15. _ = _error;
  16. return localStorage['log'] = content;
  17. }
  18. };
  19. Log.log = function() {
  20. var args, content;
  21. args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  22. console.log.apply(console, args);
  23. content = args.map(Log.str.bind(Log)).join(' ') + '\n';
  24. return _writeLogToLocalStorage(content);
  25. };
  26. Log.error = function() {
  27. var args, content;
  28. args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
  29. console.error.apply(console, args);
  30. content = args.map(Log.str.bind(Log)).join(' ');
  31. localStorage['logLastError'] = content;
  32. return _writeLogToLocalStorage('ERROR: ' + content + '\n');
  33. };
  34. unhandledPromises = [];
  35. unhandledPromisesId = [];
  36. unhandledPromisesNextId = 1;
  37. Promise.onPossiblyUnhandledRejection(function(reason, promise) {
  38. Log.error("[" + unhandledPromisesNextId + "] Unhandled rejection:\n", reason);
  39. unhandledPromises.push(promise);
  40. unhandledPromisesId.push(unhandledPromisesNextId);
  41. return unhandledPromisesNextId++;
  42. });
  43. Promise.onUnhandledRejectionHandled(function(promise) {
  44. var index;
  45. index = unhandledPromises.indexOf(promise);
  46. Log.log("[" + unhandledPromisesId[index] + "] Rejection handled!", promise);
  47. unhandledPromises.splice(index, 1);
  48. return unhandledPromisesId.splice(index, 1);
  49. });
  50. iconCache = {};
  51. drawContext = null;
  52. drawError = null;
  53. drawIcon = function(resultColor, profileColor) {
  54. var cacheKey, e, icon, size, _i, _len, _ref;
  55. cacheKey = "omega+" + (resultColor != null ? resultColor : '') + "+" + profileColor;
  56. icon = iconCache[cacheKey];
  57. if (icon) {
  58. return icon;
  59. }
  60. try {
  61. if (drawContext == null) {
  62. drawContext = document.getElementById('canvas-icon').getContext('2d');
  63. }
  64. icon = {};
  65. _ref = [16, 19, 24, 32, 38];
  66. for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  67. size = _ref[_i];
  68. drawContext.scale(size, size);
  69. drawContext.clearRect(0, 0, 1, 1);
  70. if (resultColor != null) {
  71. drawOmega(drawContext, resultColor, profileColor);
  72. } else {
  73. drawOmega(drawContext, profileColor);
  74. }
  75. drawContext.setTransform(1, 0, 0, 1, 0, 0);
  76. icon[size] = drawContext.getImageData(0, 0, size, size);
  77. if (icon[size].data[3] === 255) {
  78. throw new Error('Icon drawing blocked by privacy.resistFingerprinting.');
  79. }
  80. }
  81. } catch (_error) {
  82. e = _error;
  83. if (drawError == null) {
  84. drawError = e;
  85. Log.error(e);
  86. Log.error('Profile-colored icon disabled. Falling back to static icon.');
  87. }
  88. icon = null;
  89. }
  90. return iconCache[cacheKey] = icon;
  91. };
  92. charCodeUnderscore = '_'.charCodeAt(0);
  93. isHidden = function(name) {
  94. return name.charCodeAt(0) === charCodeUnderscore && name.charCodeAt(1) === charCodeUnderscore;
  95. };
  96. dispName = function(name) {
  97. return chrome.i18n.getMessage('profile_' + name) || name;
  98. };
  99. actionForUrl = function(url) {
  100. return options.ready.then(function() {
  101. var request;
  102. request = OmegaPac.Conditions.requestFromUrl(url);
  103. return options.matchProfile(request);
  104. }).then(function(_arg) {
  105. var attached, condition, condition2Str, current, currentName, details, direct, icon, name, profile, profileColor, realCurrentName, result, resultColor, results, shortTitle, _i, _len, _ref, _ref1;
  106. profile = _arg.profile, results = _arg.results;
  107. current = options.currentProfile();
  108. currentName = dispName(current.name);
  109. if (current.profileType === 'VirtualProfile') {
  110. realCurrentName = current.defaultProfileName;
  111. currentName += " [" + (dispName(realCurrentName)) + "]";
  112. current = options.profile(realCurrentName);
  113. }
  114. details = '';
  115. direct = false;
  116. attached = false;
  117. condition2Str = function(condition) {
  118. return condition.pattern || OmegaPac.Conditions.str(condition);
  119. };
  120. for (_i = 0, _len = results.length; _i < _len; _i++) {
  121. result = results[_i];
  122. if (Array.isArray(result)) {
  123. if (result[1] == null) {
  124. attached = false;
  125. name = result[0];
  126. if (name[0] === '+') {
  127. name = name.substr(1);
  128. }
  129. if (isHidden(name)) {
  130. attached = true;
  131. } else if (name !== realCurrentName) {
  132. details += chrome.i18n.getMessage('browserAction_defaultRuleDetails');
  133. details += " => " + (dispName(name)) + "\n";
  134. }
  135. } else if (result[1].length === 0) {
  136. if (result[0] === 'DIRECT') {
  137. details += chrome.i18n.getMessage('browserAction_directResult');
  138. details += '\n';
  139. direct = true;
  140. } else {
  141. details += "" + result[0] + "\n";
  142. }
  143. } else if (typeof result[1] === 'string') {
  144. details += "" + result[1] + " => " + result[0] + "\n";
  145. } else {
  146. condition = condition2Str((_ref = result[1].condition) != null ? _ref : result[1]);
  147. details += "" + condition + " => ";
  148. if (result[0] === 'DIRECT') {
  149. details += chrome.i18n.getMessage('browserAction_directResult');
  150. details += '\n';
  151. direct = true;
  152. } else {
  153. details += "" + result[0] + "\n";
  154. }
  155. }
  156. } else if (result.profileName) {
  157. if (result.isTempRule) {
  158. details += chrome.i18n.getMessage('browserAction_tempRulePrefix');
  159. } else if (attached) {
  160. details += chrome.i18n.getMessage('browserAction_attachedPrefix');
  161. attached = false;
  162. }
  163. condition = (_ref1 = result.source) != null ? _ref1 : condition2Str(result.condition);
  164. details += "" + condition + " => " + (dispName(result.profileName)) + "\n";
  165. }
  166. }
  167. if (!details) {
  168. details = options.printProfile(current);
  169. }
  170. resultColor = profile.color;
  171. profileColor = current.color;
  172. icon = null;
  173. if (direct) {
  174. resultColor = options.profile('direct').color;
  175. profileColor = profile.color;
  176. } else if (profile.name === current.name && options.isCurrentProfileStatic()) {
  177. resultColor = profileColor = profile.color;
  178. icon = drawIcon(profile.color);
  179. } else {
  180. resultColor = profile.color;
  181. profileColor = current.color;
  182. }
  183. if (icon == null) {
  184. icon = drawIcon(resultColor, profileColor);
  185. }
  186. shortTitle = 'Omega: ' + currentName;
  187. if (profile.name !== currentName) {
  188. shortTitle += ' => ' + profile.name;
  189. }
  190. return {
  191. title: chrome.i18n.getMessage('browserAction_titleWithResult', [currentName, dispName(profile.name), details]),
  192. shortTitle: shortTitle,
  193. icon: icon,
  194. resultColor: resultColor,
  195. profileColor: profileColor
  196. };
  197. })["catch"](function() {
  198. return null;
  199. });
  200. };
  201. storage = new OmegaTargetCurrent.Storage('local');
  202. state = new OmegaTargetCurrent.BrowserStorage(localStorage, 'omega.local.');
  203. if ((typeof chrome !== "undefined" && chrome !== null ? (_ref = chrome.storage) != null ? _ref.sync : void 0 : void 0) || (typeof browser !== "undefined" && browser !== null ? (_ref1 = browser.storage) != null ? _ref1.sync : void 0 : void 0)) {
  204. syncStorage = new OmegaTargetCurrent.Storage('sync');
  205. sync = new OmegaTargetCurrent.OptionsSync(syncStorage);
  206. if (localStorage['omega.local.syncOptions'] !== '"sync"') {
  207. sync.enabled = false;
  208. }
  209. sync.transformValue = OmegaTargetCurrent.Options.transformValueForSync;
  210. }
  211. proxyImpl = OmegaTargetCurrent.proxy.getProxyImpl(Log);
  212. state.set({
  213. proxyImplFeatures: proxyImpl.features
  214. });
  215. options = new OmegaTargetCurrent.Options(null, storage, state, Log, sync, proxyImpl);
  216. options.externalApi = new OmegaTargetCurrent.ExternalApi(options);
  217. options.externalApi.listen();
  218. if (chrome.runtime.id !== OmegaTargetCurrent.SwitchySharp.extId) {
  219. options.switchySharp = new OmegaTargetCurrent.SwitchySharp();
  220. options.switchySharp.monitor();
  221. }
  222. tabs = new OmegaTargetCurrent.ChromeTabs(actionForUrl);
  223. tabs.watch();
  224. options._inspect = new OmegaTargetCurrent.Inspect(function(url, tab) {
  225. if (url === tab.url) {
  226. options.clearBadge();
  227. tabs.processTab(tab);
  228. state.remove('inspectUrl');
  229. return;
  230. }
  231. state.set({
  232. inspectUrl: url
  233. });
  234. return actionForUrl(url).then(function(action) {
  235. var parsedUrl, title, urlDisp;
  236. if (!action) {
  237. return;
  238. }
  239. parsedUrl = OmegaTargetCurrent.Url.parse(url);
  240. if (parsedUrl.hostname === OmegaTargetCurrent.Url.parse(tab.url).hostname) {
  241. urlDisp = parsedUrl.path;
  242. } else {
  243. urlDisp = parsedUrl.hostname;
  244. }
  245. title = chrome.i18n.getMessage('browserAction_titleInspect', urlDisp) + '\n';
  246. title += action.title;
  247. chrome.browserAction.setTitle({
  248. title: title,
  249. tabId: tab.id
  250. });
  251. return tabs.setTabBadge(tab, {
  252. text: '#',
  253. color: action.resultColor
  254. });
  255. });
  256. });
  257. options.setProxyNotControllable(null);
  258. timeout = null;
  259. proxyImpl.watchProxyChange(function(details) {
  260. var internal, noRevert, notControllableBefore, parsed, reason;
  261. if (options.externalApi.disabled) {
  262. return;
  263. }
  264. if (!details) {
  265. return;
  266. }
  267. notControllableBefore = options.proxyNotControllable();
  268. internal = false;
  269. noRevert = false;
  270. switch (details['levelOfControl']) {
  271. case "controlled_by_other_extensions":
  272. case "not_controllable":
  273. reason = details['levelOfControl'] === 'not_controllable' ? 'policy' : 'app';
  274. options.setProxyNotControllable(reason);
  275. noRevert = true;
  276. break;
  277. default:
  278. options.setProxyNotControllable(null);
  279. }
  280. if (details['levelOfControl'] === 'controlled_by_this_extension') {
  281. internal = true;
  282. if (!notControllableBefore) {
  283. return;
  284. }
  285. }
  286. Log.log('external proxy: ', details);
  287. if (timeout != null) {
  288. clearTimeout(timeout);
  289. }
  290. parsed = null;
  291. timeout = setTimeout((function() {
  292. if (parsed) {
  293. return options.setExternalProfile(parsed, {
  294. noRevert: noRevert,
  295. internal: internal
  296. });
  297. }
  298. }), 500);
  299. parsed = proxyImpl.parseExternalProfile(details, options._options);
  300. });
  301. external = false;
  302. options.currentProfileChanged = function(reason) {
  303. var current, currentName, details, icon, message, realCurrentName, shortTitle, title;
  304. iconCache = {};
  305. if (reason === 'external') {
  306. external = true;
  307. } else if (reason !== 'clearBadge') {
  308. external = false;
  309. }
  310. current = options.currentProfile();
  311. currentName = '';
  312. if (current) {
  313. currentName = dispName(current.name);
  314. if (current.profileType === 'VirtualProfile') {
  315. realCurrentName = current.defaultProfileName;
  316. currentName += " [" + (dispName(realCurrentName)) + "]";
  317. current = options.profile(realCurrentName);
  318. }
  319. }
  320. details = options.printProfile(current);
  321. if (currentName) {
  322. title = chrome.i18n.getMessage('browserAction_titleWithResult', [currentName, '', details]);
  323. shortTitle = 'Omega: ' + currentName;
  324. } else {
  325. title = details;
  326. shortTitle = 'Omega: ' + details;
  327. }
  328. if (external && current.profileType !== 'SystemProfile') {
  329. message = chrome.i18n.getMessage('browserAction_titleExternalProxy');
  330. title = message + '\n' + title;
  331. shortTitle = 'Omega-Extern: ' + details;
  332. options.setBadge();
  333. }
  334. if (!current.name || !OmegaPac.Profiles.isInclusive(current)) {
  335. icon = drawIcon(current.color);
  336. } else {
  337. icon = drawIcon(options.profile('direct').color, current.color);
  338. }
  339. return tabs.resetAll({
  340. icon: icon,
  341. title: title,
  342. shortTitle: shortTitle
  343. });
  344. };
  345. encodeError = function(obj) {
  346. if (obj instanceof Error) {
  347. return {
  348. _error: 'error',
  349. name: obj.name,
  350. message: obj.message,
  351. stack: obj.stack,
  352. original: obj
  353. };
  354. } else {
  355. return obj;
  356. }
  357. };
  358. refreshActivePageIfEnabled = function() {
  359. if (localStorage['omega.local.refreshOnProfileChange'] === 'false') {
  360. return;
  361. }
  362. return chrome.tabs.query({
  363. active: true,
  364. lastFocusedWindow: true
  365. }, function(tabs) {
  366. var url;
  367. url = tabs[0].url;
  368. if (!url) {
  369. return;
  370. }
  371. if (url.substr(0, 6) === 'chrome') {
  372. return;
  373. }
  374. if (url.substr(0, 6) === 'about:') {
  375. return;
  376. }
  377. if (url.substr(0, 4) === 'moz-') {
  378. return;
  379. }
  380. return chrome.tabs.reload(tabs[0].id, {
  381. bypassCache: true
  382. });
  383. });
  384. };
  385. chrome.runtime.onMessage.addListener(function(request, sender, respond) {
  386. if (!(request && request.method)) {
  387. return;
  388. }
  389. options.ready.then(function() {
  390. var method, promise, target;
  391. if (request.method === 'getState') {
  392. target = state;
  393. method = state.get;
  394. } else {
  395. target = options;
  396. method = target[request.method];
  397. }
  398. if (typeof method !== 'function') {
  399. Log.error("No such method " + request.method + "!");
  400. respond({
  401. error: {
  402. reason: 'noSuchMethod'
  403. }
  404. });
  405. return;
  406. }
  407. promise = Promise.resolve().then(function() {
  408. return method.apply(target, request.args);
  409. });
  410. if (request.refreshActivePage) {
  411. promise.then(refreshActivePageIfEnabled);
  412. }
  413. if (request.noReply) {
  414. return;
  415. }
  416. promise.then(function(result) {
  417. var key, value;
  418. if (request.method === 'updateProfile') {
  419. for (key in result) {
  420. if (!__hasProp.call(result, key)) continue;
  421. value = result[key];
  422. result[key] = encodeError(value);
  423. }
  424. }
  425. return respond({
  426. result: result
  427. });
  428. });
  429. return promise["catch"](function(error) {
  430. Log.error(request.method + ' ==>', error);
  431. return respond({
  432. error: encodeError(error)
  433. });
  434. });
  435. });
  436. if (!request.noReply) {
  437. return true;
  438. }
  439. });
  440. }).call(this);