Add a basic PWA without GUI
This commit is contained in:
parent
16bd3dba28
commit
d068baf3b3
7 changed files with 135 additions and 0 deletions
48
pwa/app.js
Normal file
48
pwa/app.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
function base32_nopad_encode(slice) {
|
||||
const encoder = new base32.Encoder({ type: "rfc4648", lc: true });
|
||||
const code = encoder.write(slice).finalize();
|
||||
return code.replaceAll('=', '');
|
||||
}
|
||||
|
||||
function base64_decode(str_b64) {
|
||||
const raw_str = atob(str_b64);
|
||||
const length = raw_str.length;
|
||||
var b = [];
|
||||
for (var i = 0; i < length; i++) {
|
||||
b.push(raw_str.charCodeAt(i));
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
class KeyedAddress {
|
||||
constructor(local_part, separator, domain, key_b64) {
|
||||
this.local_part = local_part;
|
||||
this.domain = domain;
|
||||
this.separator = separator;
|
||||
this.key = base64_decode(key_b64);
|
||||
}
|
||||
|
||||
genSubAddr(sub_addr_name) {
|
||||
var hasher = sha256.hmac.create(this.key);
|
||||
hasher.update(this.local_part);
|
||||
hasher.update(this.separator);
|
||||
hasher.update(sub_addr_name);
|
||||
const hash = hasher.array();
|
||||
const offset = hash[hash.length - 1] & 0xf;
|
||||
const reduced_hash = hash.slice(offset, offset + 5);
|
||||
const code = base32_nopad_encode(reduced_hash);
|
||||
return `${this.local_part}${this.separator}${sub_addr_name}${this.separator}${code}@${this.domain}`
|
||||
}
|
||||
}
|
||||
|
||||
['a', 'b'].forEach((e) => {
|
||||
const test_addr = new KeyedAddress(e, '+', 'example.org', '11voiefK5PgCX5F1TTcuoQ==');
|
||||
console.log(test1);
|
||||
console.log('Sub-addr: ' + test_addr.genSubAddr('test'));
|
||||
});
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.register('/sw.js');
|
||||
}
|
||||
});
|
15
pwa/index.html
Normal file
15
pwa/index.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
<!doctype html>
|
||||
<html lang="en" prefix="og: https://ogp.me/ns#">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Sub-Address KEy</title>
|
||||
<link rel="manifest" href="/manifest.webmanifest">
|
||||
<script src="/vendor/base32.min.js" defer></script>
|
||||
<script src="/vendor/sha256.min.js" defer></script>
|
||||
<script src="/app.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
9
pwa/manifest.webmanifest
Normal file
9
pwa/manifest.webmanifest
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "Sub-Address KEy",
|
||||
"short_name": "sake",
|
||||
"id": "sub-address-key",
|
||||
"description": "Sub-address generator for the Sub-Address KEy (SAKE) filter.",
|
||||
"start_url": "/",
|
||||
"lang": "en",
|
||||
"display": "standalone"
|
||||
}
|
43
pwa/sw.js
Normal file
43
pwa/sw.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
const sw_version = '0.1.0';
|
||||
const cache_name = `sake-v${sw_version}`;
|
||||
const cached_files = [
|
||||
'/app.js',
|
||||
'/index.html',
|
||||
'/vendor/base32.min.js',
|
||||
'/vendor/base32.min.js.map',
|
||||
'/vendor/sha256.min.js',
|
||||
];
|
||||
|
||||
function log_message(msg) {
|
||||
console.log(`[Service Worker] v${sw_version}: ${msg}`);
|
||||
}
|
||||
|
||||
self.addEventListener('install', (e) => {
|
||||
log_message('Install');
|
||||
e.waitUntil((async () => {
|
||||
const cache = await caches.open(cache_name);
|
||||
log_message('Caching all');
|
||||
await cache.addAll(cached_files);
|
||||
})());
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (e) => {
|
||||
if (!(e.request.url.startsWith('https:') || e.request.url.startsWith('http:'))) {
|
||||
log_message(`Fetching resource failed: invalid protocol: ${e.request.url}`);
|
||||
return;
|
||||
}
|
||||
|
||||
e.respondWith((async () => {
|
||||
log_message(`Fetching resource: ${e.request.url}`);
|
||||
const cache_promise = await caches.match(e.request);
|
||||
if (cache_promise) {
|
||||
log_message(`Resource retrieved from cache: ${e.request.url}`);
|
||||
return cache_promise;
|
||||
}
|
||||
const fetch_promise = await fetch(e.request);
|
||||
const cache = await caches.open(cache_name);
|
||||
log_message(`Caching new resource: ${e.request.url}`);
|
||||
cache.put(e.request, fetch_promise.clone());
|
||||
return fetch_promise;
|
||||
})());
|
||||
});
|
10
pwa/vendor/base32.min.js
vendored
Normal file
10
pwa/vendor/base32.min.js
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
/**
|
||||
* [base32.js]{@link https://github.com/speakeasyjs/base32.js}
|
||||
*
|
||||
* @version 0.1.0
|
||||
* @author Michael Phan-Ba <michael@mikepb.com>
|
||||
* @copyright Michael Phan-Ba
|
||||
* @license MIT
|
||||
*/
|
||||
this.base32=function(t){function a(h){if(r[h])return r[h].exports;var i=r[h]={exports:{},id:h,loaded:!1};return t[h].call(i.exports,i,i.exports,a),i.loaded=!0,i.exports}var r={};return a.m=t,a.c=r,a.p="",a(0)}([function(t,a){"use strict";function r(t){if(this.buf=[],this.shift=8,this.carry=0,t){switch(t.type){case"rfc4648":this.charmap=a.rfc4648.charmap;break;case"crockford":this.charmap=a.crockford.charmap;break;case"base32hex":this.charmap=a.base32hex.charmap;break;default:throw new Error("invalid type")}t.charmap&&(this.charmap=t.charmap)}}function h(t){if(this.buf="",this.shift=3,this.carry=0,t){switch(t.type){case"rfc4648":this.alphabet=a.rfc4648.alphabet;break;case"crockford":this.alphabet=a.crockford.alphabet;break;case"base32hex":this.alphabet=a.base32hex.alphabet;break;default:throw new Error("invalid type")}t.alphabet?this.alphabet=t.alphabet:t.lc&&(this.alphabet=this.alphabet.toLowerCase())}}var i=function(t,a){return a||(a={}),t.split("").forEach(function(t,r){t in a||(a[t]=r)}),a},e={alphabet:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",charmap:{0:14,1:8}};e.charmap=i(e.alphabet,e.charmap);var s={alphabet:"0123456789ABCDEFGHJKMNPQRSTVWXYZ",charmap:{O:0,I:1,L:1}};s.charmap=i(s.alphabet,s.charmap);var c={alphabet:"0123456789ABCDEFGHIJKLMNOPQRSTUV",charmap:{}};c.charmap=i(c.alphabet,c.charmap),r.prototype.charmap=e.charmap,r.prototype.write=function(t){var a=this.charmap,r=this.buf,h=this.shift,i=this.carry;return t.toUpperCase().split("").forEach(function(t){if("="!=t){var e=255&a[t];h-=5,h>0?i|=e<<h:0>h?(r.push(i|e>>-h),h+=8,i=e<<h&255):(r.push(i|e),h=8,i=0)}}),this.shift=h,this.carry=i,this},r.prototype.finalize=function(t){return t&&this.write(t),8!==this.shift&&0!==this.carry&&(this.buf.push(this.carry),this.shift=8,this.carry=0),this.buf},h.prototype.alphabet=e.alphabet,h.prototype.write=function(t){var a,r,h,i=this.shift,e=this.carry;for(h=0;h<t.length;h++)r=t[h],a=e|r>>i,this.buf+=this.alphabet[31&a],i>5&&(i-=5,a=r>>i,this.buf+=this.alphabet[31&a]),i=5-i,e=r<<i,i=8-i;return this.shift=i,this.carry=e,this},h.prototype.finalize=function(t){return t&&this.write(t),3!==this.shift&&(this.buf+=this.alphabet[31&this.carry],this.shift=3,this.carry=0),this.buf},a.encode=function(t,a){return new h(a).finalize(t)},a.decode=function(t,a){return new r(a).finalize(t)},a.Decoder=r,a.Encoder=h,a.charmap=i,a.crockford=s,a.rfc4648=e,a.base32hex=c}]);
|
||||
//# sourceMappingURL=base32.min.js.map
|
1
pwa/vendor/base32.min.js.map
vendored
Normal file
1
pwa/vendor/base32.min.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
9
pwa/vendor/sha256.min.js
vendored
Normal file
9
pwa/vendor/sha256.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue