init-badge.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /* global Util, Params, Config, UI, Broker, Snowflake, Popup, Parse, availableLangs, WS */
  2. /*
  3. UI
  4. */
  5. class Messages {
  6. constructor(json) {
  7. this.json = json;
  8. }
  9. getMessage(m, ...rest) {
  10. let message = this.json[m].message;
  11. return message.replace(/\$(\d+)/g, (...args) => {
  12. return rest[Number(args[1]) - 1];
  13. });
  14. }
  15. }
  16. let messages = null;
  17. class BadgeUI extends UI {
  18. constructor() {
  19. super();
  20. this.popup = new Popup();
  21. }
  22. setStatus() {}
  23. missingFeature(missing) {
  24. this.popup.setEnabled(false);
  25. this.popup.setActive(false);
  26. this.popup.setStatusText(messages.getMessage('popupStatusOff'));
  27. this.setIcon('off');
  28. this.popup.setStatusDesc(missing, true);
  29. this.popup.hideButton();
  30. }
  31. turnOn() {
  32. const clients = this.active ? 1 : 0;
  33. this.popup.setChecked(true);
  34. if (clients > 0) {
  35. this.popup.setStatusText(messages.getMessage('popupStatusOn', String(clients)));
  36. this.setIcon('running');
  37. } else {
  38. this.popup.setStatusText(messages.getMessage('popupStatusReady'));
  39. this.setIcon('on');
  40. }
  41. // FIXME: Share stats from webext
  42. this.popup.setStatusDesc('');
  43. this.popup.setEnabled(true);
  44. this.popup.setActive(this.active);
  45. }
  46. turnOff() {
  47. this.popup.setChecked(false);
  48. this.popup.setStatusText(messages.getMessage('popupStatusOff'));
  49. this.setIcon('off');
  50. this.popup.setStatusDesc('');
  51. this.popup.setEnabled(false);
  52. this.popup.setActive(false);
  53. }
  54. setActive(connected) {
  55. super.setActive(connected);
  56. this.turnOn();
  57. }
  58. setIcon(status) {
  59. document.getElementById('icon').href = `assets/toolbar-${status}.ico`;
  60. }
  61. }
  62. BadgeUI.prototype.popup = null;
  63. /*
  64. Entry point.
  65. */
  66. // Defaults to opt-in.
  67. var COOKIE_NAME = "snowflake-allow";
  68. var COOKIE_LIFETIME = "Thu, 01 Jan 2038 00:00:00 GMT";
  69. var COOKIE_EXPIRE = "Thu, 01 Jan 1970 00:00:01 GMT";
  70. function setSnowflakeCookie(val, expires) {
  71. document.cookie = `${COOKIE_NAME}=${val}; path=/; expires=${expires};`;
  72. }
  73. const defaultLang = 'en_US';
  74. // Resolve as in,
  75. // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization#Localized_string_selection
  76. function getLang() {
  77. let lang = navigator.language || defaultLang;
  78. lang = lang.replace(/-/g, '_');
  79. if (availableLangs.has(lang)) {
  80. return lang;
  81. }
  82. lang = lang.split('_')[0];
  83. if (availableLangs.has(lang)) {
  84. return lang;
  85. }
  86. return defaultLang;
  87. }
  88. var debug, snowflake, config, broker, ui, log, dbg, init, update, silenceNotifications, query;
  89. (function() {
  90. snowflake = null;
  91. query = new URLSearchParams(location.search);
  92. debug = Params.getBool(query, 'debug', false);
  93. silenceNotifications = Params.getBool(query, 'silent', false);
  94. // Log to both console and UI if applicable.
  95. // Requires that the snowflake and UI objects are hooked up in order to
  96. // log to console.
  97. log = function(msg) {
  98. console.log('Snowflake: ' + msg);
  99. return snowflake != null ? snowflake.ui.log(msg) : void 0;
  100. };
  101. dbg = function(msg) {
  102. if (debug) { log(msg); }
  103. };
  104. update = function() {
  105. const cookies = Parse.cookie(document.cookie);
  106. if (cookies[COOKIE_NAME] !== '1') {
  107. ui.turnOff();
  108. snowflake.disable();
  109. log('Currently not active.');
  110. return;
  111. }
  112. if (!Util.hasWebRTC()) {
  113. ui.missingFeature(messages.getMessage('popupWebRTCOff'));
  114. snowflake.disable();
  115. return;
  116. }
  117. WS.probeWebsocket(config.relayAddr)
  118. .then(
  119. () => {
  120. ui.turnOn();
  121. dbg('Contacting Broker at ' + broker.url);
  122. log('Starting snowflake');
  123. snowflake.setRelayAddr(config.relayAddr);
  124. snowflake.beginWebRTC();
  125. },
  126. () => {
  127. ui.missingFeature(messages.getMessage('popupBridgeUnreachable'));
  128. snowflake.disable();
  129. log('Could not connect to bridge.');
  130. }
  131. );
  132. };
  133. init = function() {
  134. ui = new BadgeUI();
  135. if (!Util.hasCookies()) {
  136. ui.missingFeature(messages.getMessage('badgeCookiesOff'));
  137. return;
  138. }
  139. config = new Config;
  140. config.proxyType = "badge";
  141. if ('off' !== query.get('ratelimit')) {
  142. config.rateLimitBytes = Params.getByteCount(query, 'ratelimit', config.rateLimitBytes);
  143. }
  144. broker = new Broker(config);
  145. snowflake = new Snowflake(config, ui, broker);
  146. log('== snowflake proxy ==');
  147. update();
  148. document.getElementById('enabled').addEventListener('change', (event) => {
  149. if (event.target.checked) {
  150. setSnowflakeCookie('1', COOKIE_LIFETIME);
  151. } else {
  152. setSnowflakeCookie('', COOKIE_EXPIRE);
  153. }
  154. update();
  155. })
  156. };
  157. // Notification of closing tab with active proxy.
  158. window.onbeforeunload = function() {
  159. if (
  160. !silenceNotifications &&
  161. snowflake !== null &&
  162. ui.active
  163. ) {
  164. return Snowflake.MESSAGE.CONFIRMATION;
  165. }
  166. return null;
  167. };
  168. window.onunload = function() {
  169. if (snowflake !== null) { snowflake.disable(); }
  170. return null;
  171. };
  172. window.onload = function() {
  173. fetch(`./_locales/${getLang()}/messages.json`)
  174. .then((res) => {
  175. if (!res.ok) { return; }
  176. return res.json();
  177. })
  178. .then((json) => {
  179. messages = new Messages(json);
  180. Popup.fill(document.body, (m) => {
  181. return messages.getMessage(m);
  182. });
  183. init();
  184. });
  185. }
  186. }());