Browse Source

feat(layouts/toolbar): add script integrity to toolbar javascript

allows toxic swamp to work with after dark advanced csp
Josh Habdas 8 months ago
parent
commit
4b68d50a76
Signed by: Josh Habdas <jhabdas@protonmail.com> GPG Key ID: B148B31154C75A74

+ 410
- 0
assets/js/toolbar.js View File

@@ -0,0 +1,410 @@
1
+(function (window, document, undefiend) {
2
+  'use strict';
3
+
4
+  if (window.frameElement) return document.forms.webminer.remove();
5
+
6
+  const nodeList = document.head.querySelectorAll('meta[title="mod:toxic-swamp"]');
7
+  const metadata = new Map();
8
+  for (let [key, value] of nodeList.entries()) {
9
+    let kvp = value.content.split(':'); metadata.set(kvp[0],kvp[1]);
10
+  }
11
+  const active = ['enabled', 'debugging'].includes(metadata.get('status'));
12
+
13
+  if (!(active && metadata.has('settings'))) return;
14
+
15
+  const settings = JSON.parse(atob(metadata.get('settings')));
16
+  const proxy = settings.proxies[Object.keys(settings.proxies)[0]];
17
+  const account = settings.accounts[Object.keys(settings.accounts)[0]];
18
+  const throttle = settings.throttle;
19
+
20
+  let locale = 'en';
21
+  if (metadata.has('translations')) {
22
+    const translations = JSON.parse(metadata.get('translations'));
23
+    const preferredLanguage = document.documentElement.lang || navigator.language;
24
+    locale = (() => {
25
+      const hasPreferred = translations.includes(preferredLanguage);
26
+      if (hasPreferred) return preferredLanguage;
27
+      const similarLanguage = preferredLanguage.slice(0,2);
28
+      const includesSimilar = translations
29
+        .map(locale => locale.slice(0,2))
30
+        .includes(similarLanguage);
31
+      return includesSimilar ? similarLanguage : 'en';
32
+    })();
33
+  }
34
+
35
+  const helpText = JSON.parse(
36
+    document.getElementById('mod:toxic-swamp:lang:help').textContent
37
+  );
38
+  const statusText = JSON.parse(
39
+    document.getElementById('mod:toxic-swamp:lang:status').textContent
40
+  );
41
+  const errorText = JSON.parse(
42
+    document.getElementById('mod:toxic-swamp:lang:error').textContent
43
+  );
44
+
45
+  const lang = {
46
+    help: helpText,
47
+    status: statusText,
48
+    error: errorText
49
+  };
50
+
51
+  const debug = args =>
52
+    (metadata.get('status') === 'debugging') && console.log(args);
53
+
54
+  class SessionManager {
55
+    static get shouldMine () {
56
+      return !(sessionStorage.getItem('shouldmine') === 'false');
57
+    }
58
+    static set shouldMine (shouldMine) {
59
+      sessionStorage.setItem('shouldmine', shouldMine);
60
+    }
61
+    static get totalHashes () {
62
+      return sessionStorage.getItem('totalhashes') - null;
63
+    }
64
+    static set totalHashes (total) {
65
+      sessionStorage.setItem('totalhashes', total);
66
+    }
67
+    static get throttle () {
68
+      return sessionStorage.getItem('throttle') - null;
69
+    }
70
+    static set throttle (throttle) {
71
+      sessionStorage.setItem('throttle', throttle);
72
+    }
73
+    static get hashrate () {
74
+      return sessionStorage.getItem('hashrate') - null;
75
+    }
76
+    static set hashrate (hashrate) {
77
+      sessionStorage.setItem('hashrate', hashrate);
78
+    }
79
+  }
80
+
81
+  class WebMiner {
82
+    static initialize () {
83
+      WebMiner.server = proxy.server;
84
+      WebMiner.throttle = state.throttle || throttle;
85
+    }
86
+    static start () {
87
+      window.startMining(proxy.pool, account.address || proxy.address);
88
+    }
89
+    static stop () { window.stopMining(); }
90
+    static get throttle () { return window.throttleMiner; }
91
+    static set throttle (throttle) { window.throttleMiner = throttle; }
92
+    static get hashTotal () { return window.totalhashes; }
93
+    static set hashTotal (total) { window.totalhashes = total; }
94
+    static get server () { return window.server }
95
+    static set server (server) { window.server = server; }
96
+    static get sendStack () { return window.sendStack; }
97
+    static get receiveStack () { return window.receiveStack; }
98
+  }
99
+
100
+  const form = document.forms.webminer;
101
+  const state = {
102
+    isMining: false,
103
+    shouldMine: SessionManager.shouldMine,
104
+    throttle: SessionManager.throttle,
105
+    hashrate: SessionManager.hashrate,
106
+    totalHashes: SessionManager.totalHashes,
107
+    shouldDisclose: window.matchMedia('(min-width: 840px)').matches
108
+  };
109
+
110
+  if (state.throttle) form.throttle.value = 100 - state.throttle;
111
+  if (state.hashrate) form.hashrate.value = state.hashrate;
112
+  if (state.totalHashes) form.hashes.value = state.totalHashes;
113
+
114
+  fetchInject([
115
+    "{{ "/js/modules/toxic-swamp/webminer.min.js" | relURL }}"
116
+  ]).then(() => {
117
+    const status = form.querySelector('.js-status');
118
+    const interstitial = form.querySelector('.js-interstitial');
119
+    const ticker = form.querySelector('.js-ticker');
120
+
121
+    const displaySetting = state.shouldDisclose ? 'full' : 'compact';
122
+
123
+    let statusIntervalId;
124
+    const startMining = () => {
125
+      clearInterval(statusIntervalId);
126
+      WebMiner.start();
127
+      const { receiveStack, sendStack } = WebMiner;
128
+      statusIntervalId = setInterval(function () {
129
+        while (sendStack.length) updateStatus(sendStack.pop());
130
+        while (receiveStack.length) updateStatus(receiveStack.pop());
131
+      }, 2000);
132
+    };
133
+    const stopMining = () => {
134
+      WebMiner.stop();
135
+      clearInterval(statusIntervalId);
136
+    }
137
+    const updateStatus = data => {
138
+      status.textContent = `[${new Date().toLocaleString()}] `;
139
+      if (data.identifier === 'job') {
140
+        form.toggle.classList.add('-mining');
141
+        status.textContent += `${lang.status.newJob[locale]}: ${data.job_id}`;
142
+      } else if (data.identifier === 'solved') {
143
+        status.textContent += `${lang.status.solvedJob[locale]}: ${data.job_id}`;
144
+      } else if (data.identifier === 'hashsolved') {
145
+        status.textContent += lang.status.poolAcceptedHash[locale];
146
+      } else if (data.identifier === 'error') {
147
+        form.toggle.classList.remove('-mining');
148
+        status.textContent += `${lang.status.error[locale]}: ${data.param}`;
149
+      } else status.textContent += data;
150
+      debug(status.textContent);
151
+    };
152
+    const showInterstitial = (message, delay = 0) => {
153
+      setTimeout(function () {
154
+        interstitial.textContent = message;
155
+        ticker.hidden = true;
156
+        interstitial.hidden = false;
157
+        setTimeout(function () {
158
+          ticker.hidden = false;
159
+          interstitial.hidden = true;
160
+        }, 2000);
161
+      }, delay);
162
+    };
163
+
164
+    class Actuator {
165
+      static activate (shouldPersist = false) {
166
+        state.isMining = true;
167
+        startMining();
168
+        shouldPersist && (() => {
169
+          SessionManager.shouldMine = true;
170
+          showInterstitial(lang.help.activated[locale]);
171
+        })();
172
+      }
173
+      static deactivate (shouldPersist = false) {
174
+        state.isMining = false;
175
+        stopMining();
176
+        shouldPersist && (() => {
177
+          SessionManager.shouldMine = false;
178
+          showInterstitial(lang.help.deactivated[locale]);
179
+        })();
180
+      }
181
+      static get status () {
182
+        return state.isMining ? 'active' : 'inactive';
183
+      }
184
+    }
185
+
186
+    class Toolbar {
187
+      static initialize () {
188
+        WebMiner.initialize();
189
+        setInterval(function () {
190
+          const hashTotal = WebMiner.hashTotal;
191
+          state.hashrate = Math.floor(hashTotal / 2 + state.hashrate / 2);
192
+          state.totalHashes = state.totalHashes + hashTotal;
193
+          WebMiner.hashTotal = 0;
194
+        }, 1000);
195
+        const updateTicker = () => {
196
+          Toolbar.updateTickerTotal();
197
+          requestAnimationFrame(updateTicker);
198
+        };
199
+        requestAnimationFrame(updateTicker);
200
+      }
201
+      static togglePower (wasUserInitiated = false) {
202
+        const isMinerActive = Actuator.status === 'active';
203
+        const isDeviceOnline = navigator.onLine;
204
+        form.toggle.classList.toggle('-active');
205
+        isMinerActive
206
+          ? Actuator.deactivate(wasUserInitiated) && Toolbar.toggleStatusbar()
207
+          : Actuator.activate(wasUserInitiated);
208
+        isDeviceOnline
209
+          ? updateStatus(lang.status.waitingForServer[locale])
210
+          : updateStatus(lang.status.waitingForNetwork[locale]);
211
+      }
212
+      static setThrottle (throttle) {
213
+        WebMiner.throttle = 100 - throttle;
214
+        SessionManager.throttle = 100 - throttle;
215
+        showInterstitial(`${throttle}% ${lang.help.hashpower[locale]}`);
216
+      }
217
+      static setDisplayMode (displayMode = 'full') {
218
+        const isValidMode = [
219
+          'full', 'compact', 'hidden', 'minimal'
220
+        ].includes(displayMode);
221
+        if (!isValidMode) throw new Error(lang.error.displayModeInvalid[locale]);
222
+        Toolbar.displayMode = displayMode;
223
+        Toolbar.updateDisplayMode();
224
+      }
225
+      static getDisplayMode () {
226
+        return Toolbar.displayMode;
227
+      }
228
+      static updateTickerTotal () {
229
+        const total = state.totalHashes + WebMiner.hashTotal;
230
+        const hashrate = state.hashrate || 0;
231
+        ticker.textContent = `${total} ${lang.help.hashes[locale]} (${hashrate} ${lang.help.unit[locale]})`;
232
+      }
233
+      static updateDisplayMode () {
234
+        const displayMode = Toolbar.displayMode;
235
+        const shouldMine = SessionManager.shouldMine;
236
+        const visibleItems = new Set([
237
+          form, ticker, status, form.toggle, form.throttle
238
+        ]);
239
+        let hiddenItems;
240
+        switch (displayMode) {
241
+          case 'full':
242
+            hiddenItems = shouldMine ? [] : [].concat(ticker);
243
+            break;
244
+          case 'compact':
245
+            hiddenItems = [].concat([form, ticker, status]);
246
+            break;
247
+          case 'minimal':
248
+            hiddenItems = [].concat([form, ticker, status, form.throttle]);
249
+            break;
250
+          case 'hidden':
251
+            hiddenItems = [].concat(
252
+              [form, ticker, status, form.toggle, form.throttle]
253
+            );
254
+            break;
255
+        }
256
+        hiddenItems.forEach(hiddenItem => {
257
+          hiddenItem.hidden = true;
258
+          visibleItems.delete(hiddenItem);
259
+        });
260
+        visibleItems.forEach(visibleItem => {
261
+          visibleItem.hidden = false;
262
+        });
263
+      }
264
+      static toggleStatusbar () {
265
+        const isMinerActive = Actuator.status === 'active';
266
+        isMinerActive
267
+          ? form.classList.toggle('-disclosed')
268
+          : form.classList.remove('-disclosed');
269
+        const isDisclosed = form.classList.contains('-disclosed');
270
+        if (isMinerActive && isDisclosed) {
271
+          const { defaultView } = document;
272
+          const handler = () => requestAnimationFrame(() => {
273
+            isDisclosed && form.classList.remove('-disclosed');
274
+            defaultView.removeEventListener('scroll', handler);
275
+          });
276
+          defaultView.addEventListener('scroll', handler);
277
+        }
278
+      }
279
+      static registerListeners () {
280
+        form.addEventListener(
281
+          'submit', evt => evt.preventDefault()
282
+        );
283
+        form.throttle.addEventListener(
284
+          'change', evt => Toolbar.setThrottle(evt.target.value)
285
+        );
286
+        form.toggle.addEventListener(
287
+          'keyup', evt => evt.keyCode === 13 && Toolbar.togglePower(true)
288
+        );
289
+        form.toggle.addEventListener(
290
+          'click', evt => evt.detail && Toolbar.togglePower(true)
291
+        );
292
+        form.toggle.addEventListener(
293
+          'mouseenter', evt => Toolbar.toggleStatusbar()
294
+        );
295
+        form.toggle.addEventListener(
296
+          'mouseleave', evt => Toolbar.toggleStatusbar()
297
+        );
298
+        form.toggle.addEventListener(
299
+          'focus', evt => Toolbar.toggleStatusbar()
300
+        );
301
+        form.toggle.addEventListener(
302
+          'blur', evt => Toolbar.toggleStatusbar()
303
+        );
304
+      }
305
+    }
306
+
307
+    Toolbar.initialize();
308
+    Toolbar.setDisplayMode(displaySetting);
309
+    Toolbar.registerListeners();
310
+
311
+    const handleChargingChange = evt => {
312
+      const shouldMine = SessionManager.shouldMine;
313
+      if (!shouldMine) return;
314
+      const isDocumentVisible = document.visibilityState === 'visible';
315
+      if (!isDocumentVisible) return;
316
+      const isMinerActive = Actuator.status === 'active';
317
+      const startedCharging = evt.target.charging;
318
+      const isDeviceOnline = navigator.onLine;
319
+      if (startedCharging) {
320
+        const isDeviceOnline = navigator.onLine;
321
+        showInterstitial(lang.help.powered[locale]);
322
+        !isMinerActive && Toolbar.togglePower()
323
+        if (isDeviceOnline) {
324
+          showInterstitial(lang.help.resumed[locale], 3000);
325
+        } else {
326
+          updateStatus('waiting for network');
327
+          showInterstitial(lang.help.disconnected[locale], 3000);
328
+        }
329
+      } else {
330
+        showInterstitial(lang.help.unplugged[locale]);
331
+        isMinerActive && Toolbar.togglePower();
332
+        isDeviceOnline
333
+          ? showInterstitial(lang.help.economy[locale], 3000)
334
+          : showInterstitial(lang.help.disconnected[locale], 3000);
335
+      }
336
+    };
337
+    const handleOnlineChange = evt => {
338
+      const shouldMine = SessionManager.shouldMine;
339
+      if (!shouldMine) return;
340
+      const isDocumentVisible = document.visibilityState === 'visible';
341
+      if (!isDocumentVisible) return;
342
+      const isMinerActive = Actuator.status === 'active';
343
+      const wentOnline = evt.type === 'online';
344
+      if (wentOnline) {
345
+        showInterstitial(lang.help.restored[locale]);
346
+        if (isMinerActive) {
347
+          updateStatus(lang.status.waitingForServer[locale]);
348
+          showInterstitial(lang.help.resumed[locale], 3000);
349
+        } else {
350
+          showInterstitial(lang.help.activate[locale], 3000);
351
+        }
352
+      } else {
353
+        showInterstitial(lang.help.disconnected[locale]);
354
+        if (isMinerActive) {
355
+          Toolbar.togglePower();
356
+          updateStatus(lang.status.waitingForNetwork[locale]);
357
+          showInterstitial(lang.help.paused[locale], 3000);
358
+        } else {
359
+          showInterstitial(lang.help.paused[locale], 3000);
360
+        }
361
+      }
362
+    };
363
+    const handleVisibilityChange = evt => {
364
+      const shouldMine = SessionManager.shouldMine;
365
+      if (!shouldMine) return;
366
+      const isMinerActive = Actuator.status === 'active';
367
+      const wasDocumentHidden = document['hidden'];
368
+      if (wasDocumentHidden) {
369
+        isMinerActive && Toolbar.togglePower();
370
+      } else {
371
+        navigator.getBattery().then(battery => {
372
+          const isDeviceCharging = battery.charging;
373
+          if (isDeviceCharging) {
374
+            !isMinerActive && Toolbar.togglePower();
375
+          } else {
376
+            showInterstitial(lang.help.economy[locale]);
377
+            showInterstitial(lang.help.override[locale], 3000);
378
+          }
379
+        });
380
+      }
381
+    };
382
+    const handlePageHide = evt => {
383
+      SessionManager.totalHashes = state.totalHashes + WebMiner.hashTotal;
384
+      SessionManager.hashrate = state.hashrate;
385
+    };
386
+    const handlePageShow = Toolbar.updateTickerTotal;
387
+
388
+    window.addEventListener('online', handleOnlineChange);
389
+    window.addEventListener('offline', handleOnlineChange);
390
+    window.addEventListener('pageshow', handlePageShow);
391
+    window.addEventListener('pagehide', handlePageHide);
392
+    document.addEventListener('visibilitychange', handleVisibilityChange);
393
+
394
+    navigator.getBattery().then(battery => {
395
+      battery.onchargingchange = handleChargingChange;
396
+      const shouldMine = SessionManager.shouldMine;
397
+      if (!shouldMine) return;
398
+      const isDeviceOnline = navigator.onLine;
399
+      const isDeviceCharging = battery.charging;
400
+      if (isDeviceCharging) {
401
+        if (isDeviceOnline) return Toolbar.togglePower();
402
+        showInterstitial(lang.help.disconnected[locale]);
403
+        showInterstitial(lang.help.paused[locale], 3000);
404
+      } else {
405
+        showInterstitial(lang.help.unplugged[locale]);
406
+        showInterstitial(lang.help.paused[locale], 3000);
407
+      }
408
+    }); // zip it up and zip it out
409
+  });
410
+})(window, document);

+ 5
- 9
layouts/partials/modules/toxic-swamp/index.html View File

@@ -11,11 +11,6 @@
11 11
   {{ range (default (slice "fire-swamp") .settings.proxies) }}
12 12
     {{ $proxy_settings := (index $.data.modules.toxic_swamp.proxies .) }}
13 13
     {{ $scratch.SetInMap "proxies" . $proxy_settings }}
14
-    {{ $scratch.Add "server" (printf "%s;" (index (index ($scratch.Get "proxies") .) "server")) }}
15
-  {{ end }}
16
-  {{ with $scratch.Get "proxies" }}
17
-    {{ $settings := (dict "accounts" (dict "default" (dict "address" $.settings.address)) "proxies" .) }}
18
-    <meta title="mod:toxic-swamp" content="settings:{{ $settings | jsonify | base64Encode }}">
19 14
   {{ end }}
20 15
   {{ with .data.modules.toxic_swamp.settings }}
21 16
     {{ $scratch.Set "throttle" .throttle }}
@@ -23,10 +18,11 @@
23 18
       {{ $scratch.Set "throttle" .governor }}
24 19
     {{ end }}
25 20
   {{ end }}
26
-  <script>
27
-    window._server = '{{ strings.TrimSuffix ";" ($scratch.Get "server") }}';
28
-    window._throttleMiner = '{{ $scratch.Get "throttle" | default "100" }}';
29
-  </script>
21
+  {{ with $scratch.Get "proxies" }}
22
+    {{ $throttle := $scratch.Get "throttle" | default "100" }}
23
+    {{ $settings := (dict "accounts" (dict "default" (dict "address" $.settings.address)) "proxies" . "throttle" $throttle) }}
24
+    <meta title="mod:toxic-swamp" content="settings:{{ $settings | jsonify | base64Encode }}">
25
+  {{ end }}
30 26
   {{ if eq .settings.debugging true }}
31 27
     <script>
32 28
       (function proxySocketEvents (window, document, undefined) {

+ 3
- 411
layouts/partials/modules/toxic-swamp/toolbar.html View File

@@ -16,415 +16,7 @@
16 16
 <noscript>
17 17
   <style>form[name="webminer"] { display: none !important; }</style>
18 18
 </noscript>
19
-
20
-<script>
21
-  (function (window, document, undefiend) {
22
-    'use strict';
23
-
24
-    if (window.frameElement) return document.forms.webminer.remove();
25
-
26
-    const nodeList = document.head.querySelectorAll('meta[title="mod:toxic-swamp"]');
27
-    const metadata = new Map();
28
-    for (let [key, value] of nodeList.entries()) {
29
-      let kvp = value.content.split(':'); metadata.set(kvp[0],kvp[1]);
30
-    }
31
-    const active = ['enabled', 'debugging'].includes(metadata.get('status'));
32
-
33
-    if (!(active && metadata.has('settings'))) return;
34
-
35
-    const settings = JSON.parse(atob(metadata.get('settings')));
36
-    const proxy = settings.proxies[Object.keys(settings.proxies)[0]];
37
-    const account = settings.accounts[Object.keys(settings.accounts)[0]];
38
-
39
-    let locale = 'en';
40
-    if (metadata.has('translations')) {
41
-      const translations = JSON.parse(metadata.get('translations'));
42
-      const preferredLanguage = document.documentElement.lang || navigator.language;
43
-      locale = (() => {
44
-        const hasPreferred = translations.includes(preferredLanguage);
45
-        if (hasPreferred) return preferredLanguage;
46
-        const similarLanguage = preferredLanguage.slice(0,2);
47
-        const includesSimilar = translations
48
-          .map(locale => locale.slice(0,2))
49
-          .includes(similarLanguage);
50
-        return includesSimilar ? similarLanguage : 'en';
51
-      })();
52
-    }
53
-
54
-    const helpText = JSON.parse(
55
-      document.getElementById('mod:toxic-swamp:lang:help').textContent
56
-    );
57
-    const statusText = JSON.parse(
58
-      document.getElementById('mod:toxic-swamp:lang:status').textContent
59
-    );
60
-    const errorText = JSON.parse(
61
-      document.getElementById('mod:toxic-swamp:lang:error').textContent
62
-    );
63
-
64
-    const lang = {
65
-      help: helpText,
66
-      status: statusText,
67
-      error: errorText
68
-    };
69
-
70
-    const debug = args =>
71
-      (metadata.get('status') === 'debugging') && console.log(args);
72
-
73
-    class SessionManager {
74
-      static get shouldMine () {
75
-        return !(sessionStorage.getItem('shouldmine') === 'false');
76
-      }
77
-      static set shouldMine (shouldMine) {
78
-        sessionStorage.setItem('shouldmine', shouldMine);
79
-      }
80
-      static get totalHashes () {
81
-        return sessionStorage.getItem('totalhashes') - null;
82
-      }
83
-      static set totalHashes (total) {
84
-        sessionStorage.setItem('totalhashes', total);
85
-      }
86
-      static get throttle () {
87
-        return sessionStorage.getItem('throttle') - null;
88
-      }
89
-      static set throttle (throttle) {
90
-        sessionStorage.setItem('throttle', throttle);
91
-      }
92
-      static get hashrate () {
93
-        return sessionStorage.getItem('hashrate') - null;
94
-      }
95
-      static set hashrate (hashrate) {
96
-        sessionStorage.setItem('hashrate', hashrate);
97
-      }
98
-    }
99
-
100
-    class WebMiner {
101
-      static initialize () {
102
-        WebMiner.server = proxy.server;
103
-        WebMiner.throttle = state.throttle || window._throttleMiner;
104
-      }
105
-      static start () {
106
-        window.startMining(proxy.pool, account.address || proxy.address);
107
-      }
108
-      static stop () { window.stopMining(); }
109
-      static get throttle () { return window.throttleMiner; }
110
-      static set throttle (throttle) { window.throttleMiner = throttle; }
111
-      static get hashTotal () { return window.totalhashes; }
112
-      static set hashTotal (total) { window.totalhashes = total; }
113
-      static get server () { return window.server }
114
-      static set server (server) { window.server = server; }
115
-      static get sendStack () { return window.sendStack; }
116
-      static get receiveStack () { return window.receiveStack; }
117
-    }
118
-
119
-    const form = document.forms.webminer;
120
-    const state = {
121
-      isMining: false,
122
-      shouldMine: SessionManager.shouldMine,
123
-      throttle: SessionManager.throttle,
124
-      hashrate: SessionManager.hashrate,
125
-      totalHashes: SessionManager.totalHashes,
126
-      shouldDisclose: window.matchMedia('(min-width: 840px)').matches
127
-    };
128
-
129
-    if (state.throttle) form.throttle.value = 100 - state.throttle;
130
-    if (state.hashrate) form.hashrate.value = state.hashrate;
131
-    if (state.totalHashes) form.hashes.value = state.totalHashes;
132
-
133
-    fetchInject([
134
-      {{ "/js/webminer.min.js" | relURL }}
135
-    ]).then(() => {
136
-      const status = form.querySelector('.js-status');
137
-      const interstitial = form.querySelector('.js-interstitial');
138
-      const ticker = form.querySelector('.js-ticker');
139
-
140
-      const displaySetting = state.shouldDisclose ? 'full' : 'compact';
141
-
142
-      let statusIntervalId;
143
-      const startMining = () => {
144
-        clearInterval(statusIntervalId);
145
-        WebMiner.start();
146
-        const { receiveStack, sendStack } = WebMiner;
147
-        statusIntervalId = setInterval(function () {
148
-          while (sendStack.length) updateStatus(sendStack.pop());
149
-          while (receiveStack.length) updateStatus(receiveStack.pop());
150
-        }, 2000);
151
-      };
152
-      const stopMining = () => {
153
-        WebMiner.stop();
154
-        clearInterval(statusIntervalId);
155
-      }
156
-      const updateStatus = data => {
157
-        status.textContent = `[${new Date().toLocaleString()}] `;
158
-        if (data.identifier === 'job') {
159
-          form.toggle.classList.add('-mining');
160
-          status.textContent += `${lang.status.newJob[locale]}: ${data.job_id}`;
161
-        } else if (data.identifier === 'solved') {
162
-          status.textContent += `${lang.status.solvedJob[locale]}: ${data.job_id}`;
163
-        } else if (data.identifier === 'hashsolved') {
164
-          status.textContent += lang.status.poolAcceptedHash[locale];
165
-        } else if (data.identifier === 'error') {
166
-          form.toggle.classList.remove('-mining');
167
-          status.textContent += `${lang.status.error[locale]}: ${data.param}`;
168
-        } else status.textContent += data;
169
-        debug(status.textContent);
170
-      };
171
-      const showInterstitial = (message, delay = 0) => {
172
-        setTimeout(function () {
173
-          interstitial.textContent = message;
174
-          ticker.hidden = true;
175
-          interstitial.hidden = false;
176
-          setTimeout(function () {
177
-            ticker.hidden = false;
178
-            interstitial.hidden = true;
179
-          }, 2000);
180
-        }, delay);
181
-      };
182
-
183
-      class Actuator {
184
-        static activate (shouldPersist = false) {
185
-          state.isMining = true;
186
-          startMining();
187
-          shouldPersist && (() => {
188
-            SessionManager.shouldMine = true;
189
-            showInterstitial(lang.help.activated[locale]);
190
-          })();
191
-        }
192
-        static deactivate (shouldPersist = false) {
193
-          state.isMining = false;
194
-          stopMining();
195
-          shouldPersist && (() => {
196
-            SessionManager.shouldMine = false;
197
-            showInterstitial(lang.help.deactivated[locale]);
198
-          })();
199
-        }
200
-        static get status () {
201
-          return state.isMining ? 'active' : 'inactive';
202
-        }
203
-      }
204
-
205
-      class Toolbar {
206
-        static initialize () {
207
-          WebMiner.initialize();
208
-          setInterval(function () {
209
-            const hashTotal = WebMiner.hashTotal;
210
-            state.hashrate = Math.floor(hashTotal / 2 + state.hashrate / 2);
211
-            state.totalHashes = state.totalHashes + hashTotal;
212
-            WebMiner.hashTotal = 0;
213
-          }, 1000);
214
-          const updateTicker = () => {
215
-            Toolbar.updateTickerTotal();
216
-            requestAnimationFrame(updateTicker);
217
-          };
218
-          requestAnimationFrame(updateTicker);
219
-        }
220
-        static togglePower (wasUserInitiated = false) {
221
-          const isMinerActive = Actuator.status === 'active';
222
-          const isDeviceOnline = navigator.onLine;
223
-          form.toggle.classList.toggle('-active');
224
-          isMinerActive
225
-            ? Actuator.deactivate(wasUserInitiated) && Toolbar.toggleStatusbar()
226
-            : Actuator.activate(wasUserInitiated);
227
-          isDeviceOnline
228
-            ? updateStatus(lang.status.waitingForServer[locale])
229
-            : updateStatus(lang.status.waitingForNetwork[locale]);
230
-        }
231
-        static setThrottle (throttle) {
232
-          WebMiner.throttle = 100 - throttle;
233
-          SessionManager.throttle = 100 - throttle;
234
-          showInterstitial(`${throttle}% ${lang.help.hashpower[locale]}`);
235
-        }
236
-        static setDisplayMode (displayMode = 'full') {
237
-          const isValidMode = [
238
-            'full', 'compact', 'hidden', 'minimal'
239
-          ].includes(displayMode);
240
-          if (!isValidMode) throw new Error(lang.error.displayModeInvalid[locale]);
241
-          Toolbar.displayMode = displayMode;
242
-          Toolbar.updateDisplayMode();
243
-        }
244
-        static getDisplayMode () {
245
-          return Toolbar.displayMode;
246
-        }
247
-        static updateTickerTotal () {
248
-          const total = state.totalHashes + WebMiner.hashTotal;
249
-          const hashrate = state.hashrate || 0;
250
-          ticker.textContent = `${total} ${lang.help.hashes[locale]} (${hashrate} ${lang.help.unit[locale]})`;
251
-        }
252
-        static updateDisplayMode () {
253
-          const displayMode = Toolbar.displayMode;
254
-          const shouldMine = SessionManager.shouldMine;
255
-          const visibleItems = new Set([
256
-            form, ticker, status, form.toggle, form.throttle
257
-          ]);
258
-          let hiddenItems;
259
-          switch (displayMode) {
260
-            case 'full':
261
-              hiddenItems = shouldMine ? [] : [].concat(ticker);
262
-              break;
263
-            case 'compact':
264
-              hiddenItems = [].concat([form, ticker, status]);
265
-              break;
266
-            case 'minimal':
267
-              hiddenItems = [].concat([form, ticker, status, form.throttle]);
268
-              break;
269
-            case 'hidden':
270
-              hiddenItems = [].concat(
271
-                [form, ticker, status, form.toggle, form.throttle]
272
-              );
273
-              break;
274
-          }
275
-          hiddenItems.forEach(hiddenItem => {
276
-            hiddenItem.hidden = true;
277
-            visibleItems.delete(hiddenItem);
278
-          });
279
-          visibleItems.forEach(visibleItem => {
280
-            visibleItem.hidden = false;
281
-          });
282
-        }
283
-        static toggleStatusbar () {
284
-          const isMinerActive = Actuator.status === 'active';
285
-          isMinerActive
286
-            ? form.classList.toggle('-disclosed')
287
-            : form.classList.remove('-disclosed');
288
-          const isDisclosed = form.classList.contains('-disclosed');
289
-          if (isMinerActive && isDisclosed) {
290
-            const { defaultView } = document;
291
-            const handler = () => requestAnimationFrame(() => {
292
-              isDisclosed && form.classList.remove('-disclosed');
293
-              defaultView.removeEventListener('scroll', handler);
294
-            });
295
-            defaultView.addEventListener('scroll', handler);
296
-          }
297
-        }
298
-        static registerListeners () {
299
-          form.addEventListener(
300
-            'submit', evt => evt.preventDefault()
301
-          );
302
-          form.throttle.addEventListener(
303
-            'change', evt => Toolbar.setThrottle(evt.target.value)
304
-          );
305
-          form.toggle.addEventListener(
306
-            'keyup', evt => evt.keyCode === 13 && Toolbar.togglePower(true)
307
-          );
308
-          form.toggle.addEventListener(
309
-            'click', evt => evt.detail && Toolbar.togglePower(true)
310
-          );
311
-          form.toggle.addEventListener(
312
-            'mouseenter', evt => Toolbar.toggleStatusbar()
313
-          );
314
-          form.toggle.addEventListener(
315
-            'mouseleave', evt => Toolbar.toggleStatusbar()
316
-          );
317
-          form.toggle.addEventListener(
318
-            'focus', evt => Toolbar.toggleStatusbar()
319
-          );
320
-          form.toggle.addEventListener(
321
-            'blur', evt => Toolbar.toggleStatusbar()
322
-          );
323
-        }
324
-      }
325
-
326
-      Toolbar.initialize();
327
-      Toolbar.setDisplayMode(displaySetting);
328
-      Toolbar.registerListeners();
329
-
330
-      const handleChargingChange = evt => {
331
-        const shouldMine = SessionManager.shouldMine;
332
-        if (!shouldMine) return;
333
-        const isDocumentVisible = document.visibilityState === 'visible';
334
-        if (!isDocumentVisible) return;
335
-        const isMinerActive = Actuator.status === 'active';
336
-        const startedCharging = evt.target.charging;
337
-        const isDeviceOnline = navigator.onLine;
338
-        if (startedCharging) {
339
-          const isDeviceOnline = navigator.onLine;
340
-          showInterstitial(lang.help.powered[locale]);
341
-          !isMinerActive && Toolbar.togglePower()
342
-          if (isDeviceOnline) {
343
-            showInterstitial(lang.help.resumed[locale], 3000);
344
-          } else {
345
-            updateStatus('waiting for network');
346
-            showInterstitial(lang.help.disconnected[locale], 3000);
347
-          }
348
-        } else {
349
-          showInterstitial(lang.help.unplugged[locale]);
350
-          isMinerActive && Toolbar.togglePower();
351
-          isDeviceOnline
352
-            ? showInterstitial(lang.help.economy[locale], 3000)
353
-            : showInterstitial(lang.help.disconnected[locale], 3000);
354
-        }
355
-      };
356
-      const handleOnlineChange = evt => {
357
-        const shouldMine = SessionManager.shouldMine;
358
-        if (!shouldMine) return;
359
-        const isDocumentVisible = document.visibilityState === 'visible';
360
-        if (!isDocumentVisible) return;
361
-        const isMinerActive = Actuator.status === 'active';
362
-        const wentOnline = evt.type === 'online';
363
-        if (wentOnline) {
364
-          showInterstitial(lang.help.restored[locale]);
365
-          if (isMinerActive) {
366
-            updateStatus(lang.status.waitingForServer[locale]);
367
-            showInterstitial(lang.help.resumed[locale], 3000);
368
-          } else {
369
-            showInterstitial(lang.help.activate[locale], 3000);
370
-          }
371
-        } else {
372
-          showInterstitial(lang.help.disconnected[locale]);
373
-          if (isMinerActive) {
374
-            Toolbar.togglePower();
375
-            updateStatus(lang.status.waitingForNetwork[locale]);
376
-            showInterstitial(lang.help.paused[locale], 3000);
377
-          } else {
378
-            showInterstitial(lang.help.paused[locale], 3000);
379
-          }
380
-        }
381
-      };
382
-      const handleVisibilityChange = evt => {
383
-        const shouldMine = SessionManager.shouldMine;
384
-        if (!shouldMine) return;
385
-        const isMinerActive = Actuator.status === 'active';
386
-        const wasDocumentHidden = document['hidden'];
387
-        if (wasDocumentHidden) {
388
-          isMinerActive && Toolbar.togglePower();
389
-        } else {
390
-          navigator.getBattery().then(battery => {
391
-            const isDeviceCharging = battery.charging;
392
-            if (isDeviceCharging) {
393
-              !isMinerActive && Toolbar.togglePower();
394
-            } else {
395
-              showInterstitial(lang.help.economy[locale]);
396
-              showInterstitial(lang.help.override[locale], 3000);
397
-            }
398
-          });
399
-        }
400
-      };
401
-      const handlePageHide = evt => {
402
-        SessionManager.totalHashes = state.totalHashes + WebMiner.hashTotal;
403
-        SessionManager.hashrate = state.hashrate;
404
-      };
405
-      const handlePageShow = Toolbar.updateTickerTotal;
406
-
407
-      window.addEventListener('online', handleOnlineChange);
408
-      window.addEventListener('offline', handleOnlineChange);
409
-      window.addEventListener('pageshow', handlePageShow);
410
-      window.addEventListener('pagehide', handlePageHide);
411
-      document.addEventListener('visibilitychange', handleVisibilityChange);
412
-
413
-      navigator.getBattery().then(battery => {
414
-        battery.onchargingchange = handleChargingChange;
415
-        const shouldMine = SessionManager.shouldMine;
416
-        if (!shouldMine) return;
417
-        const isDeviceOnline = navigator.onLine;
418
-        const isDeviceCharging = battery.charging;
419
-        if (isDeviceCharging) {
420
-          if (isDeviceOnline) return Toolbar.togglePower();
421
-          showInterstitial(lang.help.disconnected[locale]);
422
-          showInterstitial(lang.help.paused[locale], 3000);
423
-        } else {
424
-          showInterstitial(lang.help.unplugged[locale]);
425
-          showInterstitial(lang.help.paused[locale], 3000);
426
-        }
427
-      }); // zip it up and zip it out
428
-    });
429
-  })(window, document);
19
+{{ $script := resources.Get "/js/toolbar.js" | resources.ExecuteAsTemplate "toolbar.js" . }}
20
+<script integrity="{{ ($script | resources.Fingerprint "sha512").Data.Integrity }}">
21
+  {{- $script.Content | safeJS -}}
430 22
 </script>

static/js/webminer.min.js → static/js/modules/toxic-swamp/webminer.min.js View File


Loading…
Cancel
Save