Add a basic PWA without GUI

This commit is contained in:
Rodolphe Bréard 2023-07-23 15:06:57 +02:00
parent 16bd3dba28
commit d068baf3b3
7 changed files with 135 additions and 0 deletions

48
pwa/app.js Normal file
View 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
View 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
View 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
View 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
View 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

File diff suppressed because one or more lines are too long

9
pwa/vendor/sha256.min.js vendored Normal file

File diff suppressed because one or more lines are too long