Plugin: add supporter key thingy

This commit is contained in:
Val Packett 2023-10-17 19:47:54 -03:00
parent 0590d41883
commit 98f9bece17
3 changed files with 95 additions and 0 deletions

View file

@ -0,0 +1,10 @@
title: $:/plugins/valpackett/tiddlypwa/config-xsupport
tags: $:/tags/ControlPanel/TiddlyPWA
caption: Support TiddlyPWA
[[TiddlyPWA|https://tiddly.packett.cool/]] is free software in both senses of the word; you can support its development by purchasing a supporter key or signing up for a monthly subscription [[on Patreon|https://www.patreon.com/valpackett]] (if you subscribe you can ask for a key using Patreon messages).
The key does not change the behavior of the software in any way, it only gives you a warm fuzzy feeling of being a supporter of independent free software development and shows a cute message below:
<$tiddlypwa-supporter-key key={{$:/TiddlyPWASupporterKey}} />
(To apply/change the key, save it as a tiddler called [[$:/TiddlyPWASupporterKey]].)

View file

@ -10,6 +10,8 @@ Licensed under 0BSD, see license.tid.
.tiddlypwa-form input, .tiddlypwa-form button, .tiddlypwa-form details { display: block; width: 100%; margin: 0.5em 0; } .tiddlypwa-form input, .tiddlypwa-form button, .tiddlypwa-form details { display: block; width: 100%; margin: 0.5em 0; }
.tiddlypwa-form input, .tiddlypwa-form button { padding: 0.25em; border-radius: 3px; border: 1px solid #999; color: inherit; } .tiddlypwa-form input, .tiddlypwa-form button { padding: 0.25em; border-radius: 3px; border: 1px solid #999; color: inherit; }
.tiddlypwa-form-error { color: #ee1111; font-weight: bolder; } .tiddlypwa-form-error { color: #ee1111; font-weight: bolder; }
.tiddlypwa-supporter { font: 1.5em cursive; }
.tiddlypwa-supporter-tier { font-weight: bold; color: pink; text-shadow: -1px 0 0 #fff, 1px 0 0 #fff, 0 -1px #fff, 0 1px #fff, -1px -1px #fff, 1px 1px #fff, -1px 1px #fff, 1px -1px #fff, 0 0 6px rebeccapurple; display: inline-block; transform: rotateZ(-3deg); }
html body svg.tiddlypwa-image-sync-button-dynamic .tiddlypwa-image-sync-button-dynamic-idle { visibility: visible; } html body svg.tiddlypwa-image-sync-button-dynamic .tiddlypwa-image-sync-button-dynamic-idle { visibility: visible; }
html body svg.tiddlypwa-image-sync-button-dynamic .tiddlypwa-image-sync-button-dynamic-syncing { visibility: hidden; fill: <<colour dirty-indicator>>; } html body svg.tiddlypwa-image-sync-button-dynamic .tiddlypwa-image-sync-button-dynamic-syncing { visibility: hidden; fill: <<colour dirty-indicator>>; }
html body.tiddlypwa-syncing svg.tiddlypwa-image-sync-button-dynamic .tiddlypwa-image-sync-button-dynamic-idle { visibility: hidden; } html body.tiddlypwa-syncing svg.tiddlypwa-image-sync-button-dynamic .tiddlypwa-image-sync-button-dynamic-idle { visibility: hidden; }

View file

@ -0,0 +1,83 @@
/*\
title: $:/plugins/valpackett/tiddlypwa/supporter-key
type: application/javascript
module-type: widget
Licensed under 0BSD, see license.tid.
Formatted with `deno fmt`.
\*/
/// <reference types="npm:tw5-typed" />
(function () {
'use strict';
if (!$tw.browser || !('crypto' in window)) return;
const b64udec = (x) => Uint8Array.from(atob(x.replace(/_/g, '/').replace(/-/g, '+')), (c) => c.charCodeAt(0));
const pubkey = crypto.subtle.importKey(
'jwk',
{
'crv': 'P-256',
'kid': 'xuf485BsGcWBWQF4GHvz32DM39Ls0zYLLTkczSBbdmw',
'kty': 'EC',
'use': 'sig',
'x': 'HU_Qr8MJQdj58A7cDHXggO_-SGN-kaFc1kMnwH34vvM',
'y': 'XMl52EulmwbzOoMmVWJEnZ6hw2UG4_xEixNUUU_TPwM',
},
{
name: 'ECDSA',
namedCurve: 'P-256',
},
true,
['verify'],
);
const Widget = require('$:/core/modules/widgets/widget.js').widget;
exports['tiddlypwa-supporter-key'] = class TSK extends Widget {
#parent;
render(parent, nextSibling) {
this.computeAttributes();
if (parent) this.#parent = parent;
const node = this.document.createElement('p');
this.#parent.insertBefore(node, nextSibling);
this.domNodes.push(node);
const key = this.getAttribute('key', '');
if (key.length === 0) {
node.innerText = '-key not found-';
return;
}
const [prot, pl, sig] = key.trim().split('.');
if (!prot || !pl || !sig) {
node.innerText = '-key format not valid-';
return;
}
node.innerText = '...';
pubkey
.then((k) =>
crypto.subtle.verify(
{ name: 'ECDSA', hash: { name: 'SHA-256' } },
k,
b64udec(sig),
new TextEncoder().encode(prot + '.' + pl),
)
)
.then((res) => {
if (res) node.innerHTML = JSON.parse(new TextDecoder().decode(b64udec(pl))).h;
else node.innerText = '-key signature not valid-';
})
.catch((e) => {
console.error(e);
node.innerText = '-key validation error-';
});
}
refresh(_chg) {
if (this.computeAttributes().key) {
this.refreshSelf();
return true;
}
return false;
}
};
})();