From 69adc9a3512752d627e126dde85c859fcba9fb63 Mon Sep 17 00:00:00 2001 From: ken Date: Sun, 25 Jun 2017 06:48:17 +0000 Subject: [PATCH] improved structure/functionality --- client.js | 5 ++ host.js | 17 ++++ main.js | 145 +++++++++++++++++++++++++-------- package.json | 1 + remote-server.html | 40 ++++----- skel.html | 10 +++ stunnel.cert | 29 +++++++ stunnel.key | 28 +++++++ www/android-icon-144x144.png | Bin 0 -> 1616 bytes www/android-icon-192x192.png | Bin 0 -> 1377 bytes www/android-icon-36x36.png | Bin 0 -> 999 bytes www/android-icon-48x48.png | Bin 0 -> 1242 bytes www/android-icon-72x72.png | Bin 0 -> 1141 bytes www/android-icon-96x96.png | Bin 0 -> 1254 bytes www/apple-icon-114x114.png | Bin 0 -> 1431 bytes www/apple-icon-120x120.png | Bin 0 -> 1314 bytes www/apple-icon-144x144.png | Bin 0 -> 1616 bytes www/apple-icon-152x152.png | Bin 0 -> 1837 bytes www/apple-icon-180x180.png | Bin 0 -> 1815 bytes www/apple-icon-57x57.png | Bin 0 -> 1122 bytes www/apple-icon-60x60.png | Bin 0 -> 1111 bytes www/apple-icon-72x72.png | Bin 0 -> 1141 bytes www/apple-icon-76x76.png | Bin 0 -> 1252 bytes www/apple-icon-precomposed.png | Bin 0 -> 1947 bytes www/apple-icon.png | Bin 0 -> 1947 bytes www/browserconfig.xml | 2 + www/favicon-16x16.png | Bin 0 -> 913 bytes www/favicon-32x32.png | Bin 0 -> 1086 bytes www/favicon-96x96.png | Bin 0 -> 1254 bytes www/favicon.ico | Bin 0 -> 1150 bytes www/manifest.json | 41 ++++++++++ www/ms-icon-144x144.png | Bin 0 -> 1616 bytes www/ms-icon-150x150.png | Bin 0 -> 1633 bytes www/ms-icon-310x310.png | Bin 0 -> 4289 bytes www/ms-icon-70x70.png | Bin 0 -> 1122 bytes 35 files changed, 263 insertions(+), 55 deletions(-) create mode 100644 client.js create mode 100644 host.js create mode 100644 skel.html create mode 100644 stunnel.cert create mode 100644 stunnel.key create mode 100644 www/android-icon-144x144.png create mode 100644 www/android-icon-192x192.png create mode 100644 www/android-icon-36x36.png create mode 100644 www/android-icon-48x48.png create mode 100644 www/android-icon-72x72.png create mode 100644 www/android-icon-96x96.png create mode 100644 www/apple-icon-114x114.png create mode 100644 www/apple-icon-120x120.png create mode 100644 www/apple-icon-144x144.png create mode 100644 www/apple-icon-152x152.png create mode 100644 www/apple-icon-180x180.png create mode 100644 www/apple-icon-57x57.png create mode 100644 www/apple-icon-60x60.png create mode 100644 www/apple-icon-72x72.png create mode 100644 www/apple-icon-76x76.png create mode 100644 www/apple-icon-precomposed.png create mode 100644 www/apple-icon.png create mode 100644 www/browserconfig.xml create mode 100644 www/favicon-16x16.png create mode 100644 www/favicon-32x32.png create mode 100644 www/favicon-96x96.png create mode 100644 www/favicon.ico create mode 100644 www/manifest.json create mode 100644 www/ms-icon-144x144.png create mode 100644 www/ms-icon-150x150.png create mode 100644 www/ms-icon-310x310.png create mode 100644 www/ms-icon-70x70.png diff --git a/client.js b/client.js new file mode 100644 index 0000000..3f0aeec --- /dev/null +++ b/client.js @@ -0,0 +1,5 @@ +const body = document.createElement('body') +const root = document.createElement('div') +document.title = "Strapp.io Client" +body.appendChild(root) +document.body = body diff --git a/host.js b/host.js new file mode 100644 index 0000000..2700506 --- /dev/null +++ b/host.js @@ -0,0 +1,17 @@ +const body = document.createElement('body') +const root = document.createElement('div') +document.title = "Strapp.io Host" +if ("WebSocket" in window) { + const wsock = new WebSocket("wss://" + _strapp_host + ":" + _strapp_port) + wsock.onopen = () => { + console.log("Strapped to wss://" + _strapp_host + ":" + _strapp_port) + } + wsock.onmessage = (evt) => { + console.log("Incoming connection from " + evt.data) + console.log("TODO: Open a socket to this client") + } +} else { + root.appendChild(document.createTextNode("Your browser does not support Strapp")) +} +body.appendChild(root) +document.body = body diff --git a/main.js b/main.js index 2db2240..b24e9f3 100644 --- a/main.js +++ b/main.js @@ -1,50 +1,129 @@ const fs = require('fs') const ws = require('ws') const https = require('https') -const http = require('http') const getport = require('get-port') -const argv = require('minimist')(process.argv.slice(2)) +const mime = require('mime') -const https_router_opts = { - key: fs.readFileSync('stunnel.key'), - cert: fs.readFileSync('stunnel.cert') +const argv = require('minimist')(process.argv.slice(2), { + string: [ 'ca-cert', 'ca-key', 'config', 'client-js', 'host-js', 'electron', 'port' ], + boolean: [ 'remote-host' ], + alias: { c: 'config', + j: 'client-js', + J: 'host-js', + C: 'ca-cert', + K: 'ca-key', + e: 'electron', + r: 'remote-host', + p: 'port' + }, + default: { config: undefined, + 'client-js': 'client.js', + 'host-js': 'host.js', + 'ca-cert': 'stunnel.cert', + 'ca-key': 'stunnel.key', + 'remote-host': true, + 'port': 2443 + }, + stopEarly: true, + unknown: (opt) => { + console.log(process.argv.join(" ") + '\nUnknown operator: ' + opt + ` +Usage: strapp [OPTION]... +Route https connections from a hardware port to a remote host, and initiate +peer-to-peer connection with clients. + +CONFIG + -c, --config=path Configuration file to use (/etc/strapp.conf) + - overridden by command line opts + -j, --client-js=path Path to the client Strapp code (./strapp-client.js) + -J, --host-js=path Path to the host Strapp code (./strapp-host.js) + -C, --ca-cert=path Accessible location of the CA Cert (./stunnel.cert) + -K, --ca-key=path Accessible location of the CA Key (./stunnel.key) + -p, --port=number The local port to bind HTTPS listener to (2443) + +ROUTING + -e, --electron=route Route to the local electron user (nil) + - enables optional electron dependency + -d, --dedicated=route Route all incoming connections to this route (nil) + - used in conjunction with '-e=my_route' + +(c)2017 jk software +`) + process.exit() + } +}) + +//TODO: if (argv['config'] !== undefined), read and apply to argv without overwrite +if (argv['www-path'] == undefined) + argv['www-path'] = 'www' +else if (String(argv['www-path']).endsWith('/')) + argv['www-path'] = argv['www-path'].slice(0,-1) + +const routerOpts = { + key: fs.readFileSync(argv['ca-key']), + cert: fs.readFileSync(argv['ca-cert']) } +const skelPage = String(fs.readFileSync('skel.html')).split("") +const clientJS = fs.readFileSync(argv['client-js']) +const hostJS = fs.readFileSync(argv['host-js']) +const routes = {} +const fileBuf = {} +let fbSize = 0 +fs.readdirSync(argv['www-path']).forEach((file) => { + if (fbSize++ < 50) { + fileBuf[file] = { mime: mime.lookup(argv['www-path'] + '/' + file), + data: fs.readFileSync(argv['www-path'] + '/' + file) + } + } +}) -let https_routes = {} -const https_router = https.createServer(https_router_opts, (request, response) => { - let ht_argv = request.url.slice(1).split("?") - console.log(ht_argv) - if (ht_argv[0] in https_routes) { - response.writeHead(200, { 'Content-Type': 'text/plain' }) - response.write('You are a remote client\r\n') - let route = https_routes[ht_argv[0]] - response.write('You should connect to ' + route.host + "\r\nOn port: " + route.port + "\r\n") +const router = https.createServer(routerOpts, (request, response) => { + const htArgv = request.url.slice(1).split("?") + let routeName = htArgv[0].split('/')[0] + if (routeName === '') + routeName = 'index.html' + if (routeName.indexOf('.') != -1) { + if (routeName in fileBuf) { + response.writeHead(200, { 'Content-Type': fileBuf[routeName].mime }) + response.write(fileBuf[routeName].data) + } + else { + if ('404.html' in fileBuf) { + response.writeHead(404, fileBuf['404.html'].mime) + response.write(fileBuf['404.html'].data) + } + else + response.writeHead(404) + } response.end() } - else if (ht_argv[0].indexOf(".") == -1) { - https_routes[ht_argv[0]] = 'true' + else if (routeName in routes) { + const route = routes[routeName] response.writeHead(200, { 'Content-Type': 'text/html' }) - let new_route = {} - new_route.host = request.headers['x-forwarded-for'] || request.connection.remoteAddress + response.write(skelPage[0] + clientJS + skelPage[1]) + response.end() + route.socket.send(request.headers['x-forwarded-for'] || request.connection.remoteAddress) + } + else { + routes[htArgv[0]] = true + const newRoute = {} + newRoute.host = request.headers['x-forwarded-for'] || request.connection.remoteAddress getport().then( (port) => { - new_route.port = port - new_route.httpd = https.createServer(https_router_opts, (request, response) => { - }).listen(port) - new_route.ws = new ws.Server( { server: new_route.httpd } ) - new_route.ws.on('connection', (ws) => { console.log("socket connected"); ws.send("CONNECTED") } ) - new_route.ws.on('message', (msg) => { console.log("Received message" + msg) }) - console.log("Listening for websocket socket " + new_route.port + " on " + new_route.host) - console.log(new_route) - https_routes[ht_argv[0]] = new_route + newRoute.port = port + newRoute.httpd = https.createServer(routerOpts, (request, response) => { + }).listen(newRoute.port) + + newRoute.ws = new ws.Server( { server: newRoute.httpd } ) + newRoute.ws.on('connection', (ws) => { console.log("socket connected"); newRoute.socket = ws; ws.send("CONNECTED") } ) + newRoute.ws.on('message', (msg) => { console.log("Received message" + msg) }) + console.log("Listening for websocket " + newRoute.host + " on port " + newRoute.port) + routes[htArgv[0]] = newRoute }).then(() => { - let str = String(fs.readFileSync('remote-server.html')) - response.write(str.replace("$HOST","www.strapp.io").replace("$PORT",new_route.port)) + response.writeHead(200, { 'Content-Type': 'text/html' }) + response.write(skelPage[0] + 'const _strapp_host = \'www.strapp.io\'\n\tconst _strapp_port = \'' + newRoute.port + '\'\n' + hostJS + skelPage[1]) response.end() }) } -}).listen(2443) - - +}).listen(argv['port']) -if ("electron" in process.versions); +//TODO: if ("electron" in process.versions) open a local renderwindow, and route to it diff --git a/package.json b/package.json index b03b4c4..b041e15 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "dependencies": { "electron": "^1.6.11", "get-port": "^3.1.0", + "mime": "^1.3.6", "minimist": "^1.2.0", "ws": "^3.0.0" } diff --git a/remote-server.html b/remote-server.html index 3d4ee3c..2b65a20 100644 --- a/remote-server.html +++ b/remote-server.html @@ -1,28 +1,24 @@ - + strappDiv.innerHTML = "Sent test" + } + wsock.onmessage = (evt) => { + strappDiv.innerHTML = "Got Response
" + evt.data + } + } else { + strappDiv.innerHTML = "Your browser does not support Strapp" + } + - -
- Unterminated -
- diff --git a/skel.html b/skel.html new file mode 100644 index 0000000..0342496 --- /dev/null +++ b/skel.html @@ -0,0 +1,10 @@ + + + + + Strapp.io + + + diff --git a/stunnel.cert b/stunnel.cert new file mode 100644 index 0000000..6ae9532 --- /dev/null +++ b/stunnel.cert @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIE/TCCA+WgAwIBAgISA8tDqABqbcv2/gK8/q12IhazMA0GCSqGSIb3DQEBCwUA +MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD +ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xNzA2MjMwMjI1MDBaFw0x +NzA5MjEwMjI1MDBaMBgxFjAUBgNVBAMTDXd3dy5zdHJhcHAuaW8wggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCh1tSTfA1JAxsNJTwhCgwPMeY9Lib0PjiO +/EOy0optOeDqOJwB1C0HRnTg4NSoj9q+B0joKuvjvLhYBob7sRdjqiDPsq78aESC +ENP5rz1+O73wEtcv3G9z5IvCcnicYrWdRYipBgFiV6rxkzwZFBsxxy6W47/jjadX +G1nhWTKy1Vkd2BjnB/B138qhJe0z45pRCvPVIaPlalQvSEiqrLhIOfmc1apFjBis +cjI57bQ6AswgoELY5SP+edLVy3ZM/XAS+6aPVJumzQ+XCy3vCvOh0aJfoDa0Ewne +DeMcTU9G3YicPOHwR5HT3Cd7OK+o7y4Aib0LJn1B1wbEwE8btkTRAgMBAAGjggIN +MIICCTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF +BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFHNyMj5LuteK5+BbAiTD7Vfqjv+n +MB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUFBwEBBGMw +YTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNyeXB0Lm9y +ZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNyeXB0Lm9y +Zy8wGAYDVR0RBBEwD4INd3d3LnN0cmFwcC5pbzCB/gYDVR0gBIH2MIHzMAgGBmeB +DAECATCB5gYLKwYBBAGC3xMBAQEwgdYwJgYIKwYBBQUHAgEWGmh0dHA6Ly9jcHMu +bGV0c2VuY3J5cHQub3JnMIGrBggrBgEFBQcCAjCBngyBm1RoaXMgQ2VydGlmaWNh +dGUgbWF5IG9ubHkgYmUgcmVsaWVkIHVwb24gYnkgUmVseWluZyBQYXJ0aWVzIGFu +ZCBvbmx5IGluIGFjY29yZGFuY2Ugd2l0aCB0aGUgQ2VydGlmaWNhdGUgUG9saWN5 +IGZvdW5kIGF0IGh0dHBzOi8vbGV0c2VuY3J5cHQub3JnL3JlcG9zaXRvcnkvMA0G +CSqGSIb3DQEBCwUAA4IBAQABrj60dXDaiixw7Qd7it5YqLp0m5Gj8BR843pocoFv +cdyeTPlyL0xWRkOn3++M2oN2MS6DXjt8nVoYrToGxqmgcpuwcn+iOv+yWiiaJWl2 +LWcfZxhD5rbSJGvkbXOI9nyTBcXF3t0rsKS+GJACaZkA0w9e+kADhJ0eGrbf30KT +l5D9B7qX2LJaM+zcDY8gj3+tDj2hBK07JMekjC1C0y+Tq0WnvZZ3dw2YD4Jd8Ofc +OmR20LGv4xz4wCJ7E3rqMqpUVgAfyM7yiQrnLcggIiMQRqACqJk4yn0+agsM6P2n +Ru+x1nbXw87XsGwno5dYnqlonbUMrDBOFKX/jtoXjy+/ +-----END CERTIFICATE----- diff --git a/stunnel.key b/stunnel.key new file mode 100644 index 0000000..99661cb --- /dev/null +++ b/stunnel.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCh1tSTfA1JAxsN +JTwhCgwPMeY9Lib0PjiO/EOy0optOeDqOJwB1C0HRnTg4NSoj9q+B0joKuvjvLhY +Bob7sRdjqiDPsq78aESCENP5rz1+O73wEtcv3G9z5IvCcnicYrWdRYipBgFiV6rx +kzwZFBsxxy6W47/jjadXG1nhWTKy1Vkd2BjnB/B138qhJe0z45pRCvPVIaPlalQv +SEiqrLhIOfmc1apFjBiscjI57bQ6AswgoELY5SP+edLVy3ZM/XAS+6aPVJumzQ+X +Cy3vCvOh0aJfoDa0EwneDeMcTU9G3YicPOHwR5HT3Cd7OK+o7y4Aib0LJn1B1wbE +wE8btkTRAgMBAAECggEAZYNvi6NAYg/EpBY7BS5cKhvOo4mTfZiZuXaasExH8ANi +BQjFMpB4Phv/rB7axXCWcKP5I0fo9sylhPFzMeT/GtDYC++0uzZb4onTrMYy+D9Z +AIGQ4MCQWE1/LNTIuq9f4+p9sifGLn13CFimVcS62hpqKtNoxb9Qu964HhXpKyqQ +MeSZhJsN9/ixdAVW/JWMEcOZLtttaznJ/JPZu5cvt0cis86Iir4I89fowdFO3V+h +WI03Ax/aafcthS1zOg4QLl/mCL69yURQPC1dYhDZ7pH/ZEqgNxp1B3+Sio37fe2A +EJFx8kyb4+Jku7KkIYw8L+OelYxLlwEYjHkuQ+puwQKBgQDWHSA7COEvJxRScq0G +07TaCmHMvhG+GtCDSLiST8pip64RDN/u3OpMn2MlLYQMSQB4XGdklBfb3IesbpLl +DWIdMxQ4H1GFgfSQYiN5WzF2U6A1OG7IaWGc17hrB6hcFKrW6K8hstaboMEgtUnV +87N9T4sr4G7B38bxI2f+VYi+jQKBgQDBf8d2yGBhfDBruNrTx+eN4ywccC+uWaOS +vEcV1qf5hQDS2PA/7AQkxMofDDNZFak7baTbFAKhH+sUKriTyth2vgakHVS5xxJH +WvuGJhttHheh35B1lGKVvYsJqpMG5oPpySqLLu1/gBzw0H+tnbdCA/iF//qodLD0 +vUIg6ksAVQKBgGZjz0Hr4SOXYJR82lllbBrI1DQAwKNUV1owsHLnTTUYUpk8uumT +I0g5AESLG5Z0YpEsPxVN7IrrTsYaqox2dfDYuFaOQ4HAv588DxK9lU2sd/R7ZB7a +ph9G2Z31L4G5MGlNJFLNHuuVWEW36/Mwcyj9nOQCk3SK+qvd7qElbhsRAoGAXlzK +EQs2tVOy6VWEobLjITaf1F6BYi0kr/JRWD0OPYi3FhvlTcbzXlr5lpqEj/UYSnr1 +4kCn55uBMJyE1s4dMgsJgg8ruk1yhInCD3GV/mimbbJw6GYsjYmZvGUKvlq8Cc6o +iKeh+oOnmWiUWz6GmBMHp5Fl07DUewWwsgyP9uECgYEAsdIajEA77zX0Zi/58DwC +5OBpM5UhLBqjYPIFZgE+iowMRc79A484IBxVXnoYdGeDE1qvu4RTCggpCSmVuOFM +kd+HY6zQNv1cVn/VXyJ2p1OK3J2gxY4nSrmy7zlIj3e7AOSswK0arenkuUlpBo7o +G4kQUXI2Zjzw98EmRT60Yrg= +-----END PRIVATE KEY----- diff --git a/www/android-icon-144x144.png b/www/android-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc35dc619dc3163c88f014d2383a1df3635a01d GIT binary patch literal 1616 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=SkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpgxNL zpAc7|f>A(f2>k#5e>wN`r9f?IB|(0{3{sLp9E_!9g~3WJH!jSy`}bp~H|Mu)o=p7m z>Z-CL+{`99on7^*E?m4}Tb?|CBzY4T-1zetE#k7k~WcU7k-W9$#;5tug!a zu<84f507sD{`L0Rn!bZ+`fltRPBM$zHD7gieY$Z6Xd`2ix4TPv^yQbEfgH{PkH}&M z25w;xW@MN(M}mQYNyyX1F{I+w+dJX@hXN#y6<)d4xH?NRNK|wVhn7~N2gET>pjj_#!v4yJf;$^zVsKH>sp4aDS^So-MhCkt?>1F zD?8VVb%NT`b?@Z%GM$)qiQVI`m(hvGUtj9g=O56xe%)R`W(t2$TbuL4?M}*zlWQM; zaul9CapjBZjV~w8Jg_F-Y=ybq@~QS^XZ2NT-f@PSWfY#&sW+KE`QDKpYgNfDn|7tu z)oq-oXS?`7n>^c++-2V9GrZdwZ$7IkQrviVKO^&|w{!3A{X36Y;ljgn7r%To5IC`I z?Tve!A}4HYt=pMyrafcg4(U>8`p50DS#NV7W2(NcFNenDb5Bp#>(_^B%=b=jX;^dU z>Q==CuU9vzvOMX$b7vLPuDzWVEsZXFECtxBem6Fh%%85%#G&-Uzv;@9MbRdP`(kYX@0 zFf`XSFw-?M4KXmaGBvd_G1N9Nure@cDg7pfq9HdwB{QuOw}!78eye~Q+(0%I=ckpF zCl;kLc;+Uir}`$QXC`MWnCY48S?F3S0If99H89mRG*SpOG*ieZDJihh*Do(G*UJQ{ z24bLUz5Jr|J8f@)1~N#1Obp2=%}uhha>-9F%}vcKv9byPDlKL(T>gKzKAIY^omN&E zshQ~+B@Bj^M*Iv#tw1&6NajG*glDFdWPp@hUZcnXR3eF_#5XfHwWP8jl>zK3{erx7 z`%PhfXy*8a097#ukKe{y!UY3GgKZ!UIR`?u`d>Cchkf6s*I ziu^da^3U@N3BMj3-Spw+)w{bF9&8R?8{@wskd<4&XSze*CHJ{6=gnf!*OzBtVEXFm z;uunK>+Rj2!9s})#|oz&?NM^j;SO7<)V;`=%X{OLqkKZix+as2-q`K+-?RSj?yYKD z(`GS>-~U!S>-q1;|DL3$)fdIzTfV5t@R&sMnVP9V;i z=M{)D?pS&*`1M+CCW9sCYClckl?tf;#bb8hd3gOEr*Ca;sq5X`oe#*hFtMDUXDxqg z?K7v#N4?h>h#aW9S*^P1_SNj``6lkN0SyJ0&qi;&8YKM|Bp;!cw7Gd zt^Mm4J{eh?Ue_^je0Y#}`rl^vmB;VSnzb&6g=x!oo16913SaN7TdR9l^a!JgeeJj3 zmvh|H@1KiK31(Wru-N|Fo%Jg}u4v*q!Bg_3EL;Clb6G&c#IrB;e{TtQULU)F;qZy- zw)+-)Un)i%xZPO({`VaDkO&8}=@;9xtD_Pbt!w{$`PnTmIpO!KpWkF9C!Brq`|gQ` z`GO7%j6v=VR|O{&zg{`xK+rC0b&(13lCs?#IXNXN`XT}Lc7~EdH=Z1+*c;H0pJla* zL&wVYsW8_CVPmh8^KbhsIipgtvEk;~8v0>+%fa}|Z1sWjt_miU zvP8%-h5Zm- zy38+ak-ye5-;7mmdh7h}x`_!lUkSe6q`q$LJVE{Hlsm5!zi&#v$8T2ifBouBn%@rp jlsYbv+++A{`ZmUkmM6|0USF^ZR7`lf`njxgN@xNA{7$Pi literal 0 HcmV?d00001 diff --git a/www/android-icon-36x36.png b/www/android-icon-36x36.png new file mode 100644 index 0000000000000000000000000000000000000000..5ac6cb4f262992036a8d7966926e9a986e6781a2 GIT binary patch literal 999 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k3?#4J%UA`ZSkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?skwBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkphR7O zPlzj!9w_kt|NkbArT>7|Ym@}}1v9WP&YjmTen-POB|z|&?)ta&BAZ@M`1bGji;Bb~ z<=ZNJq1Ti9tAqr+u9mF@>S0Xsc6ZS{wY?P-K%500k;M!Q+`=Ht$S`Y;1W<6Hr;B5V z#p$t(0v*e3J=2y|F zzhYmygs$E7>QtxHMfn&LKNWVB{~rI!W?tCrz%L^sn(<=6$5uP0FH84yY=4-4?md4( zqRqjp%({k4#QBdm2Ip8m3jsP-wZt`|BqgyV)hf9t6-Y4{85o-D8kp%CnT8mcTA7+! znHXvt7+4t?w3L1mL(!0%pOTqYiCe>04L?x2aRb>-L1;F+74p6Z*Jo|&Aj zV5VoTXQ6AU0JPFX*T7WQ&`2TB&`cqtq@=(~U%$M(TrU%(8i;|a_413-@3g%I8pt34 zGBG5hG&jl0$|XO!G&eP`#L6lFsI-{DaQXk;`eCdx65q_+)RM}AR0goC^b7LR?Kg$_p_$_w0#wCdXkuw$ zY!396p_+^FCZH02By)l@t5O*ZoSddCvU>xR3PX|#4f142%gjjydS5>`uOufwT|X_c zEHgPjuUH=uG5SfVCgujlsfHFVdQ&MBb@0CK7z<^TWy literal 0 HcmV?d00001 diff --git a/www/android-icon-48x48.png b/www/android-icon-48x48.png new file mode 100644 index 0000000000000000000000000000000000000000..7dcb424f0332d98cd2ed201b69e49d50972d8d73 GIT binary patch literal 1242 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq8sKd6mGxU^Rn*LA+qju0R{0#D@T% z5LX~Qa=`!p|I>b7+7I-wUrCT(FoO_3^T9)lWp1jdxT zZtHSzEL@ShHYh}Z-J$EsIloYuPyhNCOWRcVU3zls@wxi{xgI;rJCEFad}EiFo5Im6 zUwy5ZI@a>c7j=0#P4bvRR)dwiXl7e6WIH!8&>%{1gvIebP~KUuQZ3ZmtmIf z;Ug(qbeSet|LDH(R?s2-AoFcTrtkg+4|2axI9nZ}u=mF~#d?W=gR7PsvQH z#I510hTkfn1~-rm#rbI^<%vb944%1(>8ZYn>6yvd3TArddKS8t3P3AObPY^(4UH56 z4b2oXN=gc>^!3Zj%k?rrs(~1&S}(sS{Z89kpn(h$AQM9}N^_H}tX%SwOLJ56O028` zfJ%!Q4441kt&gS#Y^Rk~MrvkyMhSzVr4c_vQ7cf5IFdO~HQ|{lB^e+km)9tA0F_80 zDe=wBO)aS`NM!)KO1~g4-F{P;ADTJ7AwX3Oh9;I4#^yk88LGJ$ZvraeM=~ckvnrLr zz{zRKBD*(0sW2p|&>&BSw9K4Tp!fB2^Gb5^)AiF5%QBPm^NRHm5u=}!YGQ6+oNAb2 wW@waXWSN#`n38CeoSK-HVqtEWlANRm)S(A--*T7cbf66kp00i_>zopr04jZ8M*si- literal 0 HcmV?d00001 diff --git a/www/android-icon-72x72.png b/www/android-icon-72x72.png new file mode 100644 index 0000000000000000000000000000000000000000..98b51d141d02ac54453637152e242f8439772620 GIT binary patch literal 1141 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 literal 0 HcmV?d00001 diff --git a/www/apple-icon-144x144.png b/www/apple-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc35dc619dc3163c88f014d2383a1df3635a01d GIT binary patch literal 1616 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 literal 0 HcmV?d00001 diff --git a/www/apple-icon-60x60.png b/www/apple-icon-60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..051fc8e40c609b4cf264046b4f5c7e84332fe41a GIT binary patch literal 1111 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 literal 0 HcmV?d00001 diff --git a/www/apple-icon-precomposed.png b/www/apple-icon-precomposed.png new file mode 100644 index 0000000000000000000000000000000000000000..dbdb0bbaebfee3fb793ee2799f3b89c805d74c21 GIT binary patch literal 1947 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 +#ffffff \ No newline at end of file diff --git a/www/favicon-16x16.png b/www/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..0c0b724393b0fcebe13c341c65ec0339dcda1942 GIT binary patch literal 913 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstUx|vage(c z!@6@aFM%9|WRD45bDP46hOx7_4S6Fo+k-*%fF5l*kY8 z32_C|bOZnY|IZDX9RjpZxg^Lhm_b^K>&nHX2$f$GULJeAX~Wt6*UQ+M;{GmSEm}HN zERy4enyOPP0}D_&W0JSKi^>+ZpEH3R&H|6fVg?3oVGw3ym^DWNC>ZbQ;us=vIXS_F z$>$6Y508#V!_?ln&5n|s1x1CQ8CWZR9%zVnm>C@4A*rFD!^E~I=}`b9r>ABjXQpJN z<&Fj$`GEaRO4czBEIJEX+!>s?cP*5-mSn+m_NBx;=kIn5X7`1a=j~j!322pSiEBhj zN@7W>RdP`(kYX@0Ff`XSFw-?M4KXmaGBvd_G1N9Nure@cDg7pfq9HdwB{QuOw}!78 zeye~Q+(0%I=ckpFCl;kLc;+Uir}`$QXC`MWnCY48S?F3S0If99H89mRG*SpOG*ieZ zDJihh*Do(G*UJQ{24bLUz5Jr|J8f@)1~N#1Obp2=%}uhha>-9F%}vcKv9byPDlKL( zT>gKzKAIY^omN&EshQ~+B@Bj^M*Iv#tw1&6NajG*glDFdWPp@hUZcnXR3eF_#5XfH zwWP8jl>zK3{erx7`%PhfXy*8a097#gTe~DWM4fvK{cO literal 0 HcmV?d00001 diff --git a/www/favicon-32x32.png b/www/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..8cff0a4f9b2e8c1de04cf8c0d2df397e33148a51 GIT binary patch literal 1086 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvI6;x#X;^) z4C~IxyacIC_6YK2V5m}KU}$JzVE6?TYIwoGP-?)y@G60U!D%xS|)&qGIxpZ0`7LL8zARb76{FKbJO57U0 zYWS@JYH$PDP@JDuQl40p%HWxsn4apJn4X!Otzf2Su4kcZsQ|RnMAyJn*U(5I(9ldF zqokz3N?*Ucyj(96q#B5Us`c`V((kmr1scd80WvWpqck_k%E~1_ximL5uf)nK0I0N> z!EpKi-TG*1z;;?$Wu#`NXOu7)S{m^)6tx1?h$EQ;RTG|>Qj!5ua(Rs+2T+M5k`mv{ z+|-iFf>Z{utMm)<((N~e`JtKP8v<0tU}$1#VQdccmZ6%9@g|@Wek5~(GpkY=44j;% zEV6q8lnO(V3JvmPNXyJg1$tjUH?JfoKV3g9u`Dw=Kd)FH5i$BnsV3$I#;JxWW`;(I tMwV%5hAD|g$*GBHDHi62DalECKplEO_bqp6P6yh+;OXk;vd$@?2>`7vGy?zt literal 0 HcmV?d00001 diff --git a/www/favicon-96x96.png b/www/favicon-96x96.png new file mode 100644 index 0000000000000000000000000000000000000000..94175e27da87de150f46c60509c6c51be5a5b651 GIT binary patch literal 1254 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy#B(j9#r85lP9bN@+X1@ak-gWR1M z)}51i3FIgwdj$D1FjT2AFf_Cc9vs4`2`V%e2NQRzJ76} z-jrKq{ohZg8kE<3IsT9LV~ywRr@!9cpJ;c~oJlf#8&~n$!nx;#p8ySGO!9VjaT2(0 z`vu71EbxddW?qD+ZZP%`4iI^q{EQ!#T zvzV{={(lh1^wd{7)MFPv`nP_^?`7djB1>iR{#&2e?qtX-^DO$M2CvNX+npZFYWGjA zdp!5o>?UJ=#+E~xbK*TTy{CtZ3KY~9ub#4N^}W}#*cs(s^`2dSJWVA_V8PcdtUiBa zUUCU}JW5*<-_T(A_S0)=5syc&tVIkwe=~E}9Al7tQ6joBubtz|uSp^M-B}Jb`ez9U zH9qY4)^9BpG~eL@gJUfd+dpB0c^Tm;PhOq8A;qz5v%%(@CL7qEbuT@cvvWo?^FOat z=B%f;nLlYe7#(0><}m;hAIcfNTokPP(JFucp}xZX9!9phM^@~$imdyCn&Y`{9XpWE zeBt`<4~2tU>rD>4tK>}oANJeRHl9iQ9esXDUYF>$zRRBU0q~!7%MGl}6NhBq{ znYpPYl?AB`U{~oEvYhz#zuJz@P!dKp~(AL>x#lFaYI*xgi+LhY%7#id4*rr2iU_ zO$xpORG$FE5kRa2#Q#aezk%v|f%r8LA4k&r1jycu18)L~pM$D}>3;*|!|Y!MPZMS&RPUqbpp_JjNYa}$Vu1;olg91a!7 zXa7*wPf7Su8h@0gALKa0$A-lpEd7#_cR*^<^AD+c7o;AMe?cLR3>=U-Xl!&jpk4q( C45=#s literal 0 HcmV?d00001 diff --git a/www/manifest.json b/www/manifest.json new file mode 100644 index 0000000..013d4a6 --- /dev/null +++ b/www/manifest.json @@ -0,0 +1,41 @@ +{ + "name": "App", + "icons": [ + { + "src": "\/android-icon-36x36.png", + "sizes": "36x36", + "type": "image\/png", + "density": "0.75" + }, + { + "src": "\/android-icon-48x48.png", + "sizes": "48x48", + "type": "image\/png", + "density": "1.0" + }, + { + "src": "\/android-icon-72x72.png", + "sizes": "72x72", + "type": "image\/png", + "density": "1.5" + }, + { + "src": "\/android-icon-96x96.png", + "sizes": "96x96", + "type": "image\/png", + "density": "2.0" + }, + { + "src": "\/android-icon-144x144.png", + "sizes": "144x144", + "type": "image\/png", + "density": "3.0" + }, + { + "src": "\/android-icon-192x192.png", + "sizes": "192x192", + "type": "image\/png", + "density": "4.0" + } + ] +} \ No newline at end of file diff --git a/www/ms-icon-144x144.png b/www/ms-icon-144x144.png new file mode 100644 index 0000000000000000000000000000000000000000..bcc35dc619dc3163c88f014d2383a1df3635a01d GIT binary patch literal 1616 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 literal 0 HcmV?d00001 diff --git a/www/ms-icon-70x70.png b/www/ms-icon-70x70.png new file mode 100644 index 0000000000000000000000000000000000000000..36f8176168ef921a1a50a428fe97fa5442185e46 GIT binary patch literal 1122 zcmeAS@N?(olHy`uVBq!ia0vp^ZXnFT3?e@WZ39v)>5jgR3=A9lx&I`x0{M)^LGDfr z>(0r%1acITJ%W507^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10VrGC( zh%1mDgy8@G|H_Mf+JP=JED7=pW?)Q8j#c~c@kyMJj=ruuCsV+Y3uk6He0sfzBk`3z z*F4|nJO2Ls_U};k9KM9P{A@N;GJMZG0%~SV@^*JIa=7Gk0?6Sk@Q5sCVBi)8VMc~o zb0mO*KRjI=Ln02py>Xha$v}WLfXl0P!3vG81wR- z7R;TQ6(#PRwfx8n)8sF|T#v1hw2~0p-+q<>8Y)%lF5H} z=Gl~MAOG>CTDW4jZ9}4Cg@eJHiY9~S9ES|9F$f2~+b^viqqZ}q_MR74vR$$F&ewnQ zKF!p5`cCVYz0bYaXA_@Yz2P!J@qGA<&_}ly^*BZbdCurIY7MWq4em)2SuAnXz9|8>t%ve12IswUVc&fowm0?0~sVhCWd5` z<|bKLx#TC8=BDPASXl)Cl@>D?F8{wp&4J!B zRC6)j1XRM0WKM8qRVssllhc$%c5i@EVMtP;L7oh0nK`LI@9XF0mE`27>!&4_WhUq6 z73(7+Mn5Ul#N5C*)iA}(&?wQ!GA+$8CDAB3H8Cy4!rU+=IY|$wLl5Y_