rune-workshop

A web ui to make runes
git clone git://jb55.com/rune-workshop
Log | Files | Refs | README

commit 3ac235f222527d06b509d8781b0b3355ef301108
Author: William Casarin <jb55@jb55.com>
Date:   Sun, 21 Aug 2022 11:18:56 -0700

initial commit

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
A.gitignore | 5+++++
AAegishjalmrRed.svg | 219+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AMakefile | 3+++
Aindex.html | 30++++++++++++++++++++++++++++++
Arune-workshop.js | 372+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aschemas.json | 2++
Astyle.css | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Async-schemas.xonsh | 26++++++++++++++++++++++++++
8 files changed, 751 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,5 @@ +lightning-master/ +lightning.tar.gz +.direnv/ +.envrc +shell.nix diff --git a/AegishjalmrRed.svg b/AegishjalmrRed.svg @@ -0,0 +1,219 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + width="550" + height="550" + version="1.1" + id="svg130" + sodipodi:docname="AegishjalmrRed.svg" + viewBox="0 0 550 550" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs134"> + <linearGradient + inkscape:collect="always" + id="linearGradient1215"> + <stop + style="stop-color:#ffc006;stop-opacity:1;" + offset="0" + id="stop1211" /> + <stop + style="stop-color:#ff2a06;stop-opacity:1;" + offset="1" + id="stop1213" /> + </linearGradient> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient1215" + id="linearGradient1217" + x1="27.528861" + y1="276.08156" + x2="527.52886" + y2="276.08156" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="namedview132" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + showgrid="false" + inkscape:zoom="1.2105668" + inkscape:cx="448.13719" + inkscape:cy="296.96833" + inkscape:window-width="1920" + inkscape:window-height="1060" + inkscape:window-x="0" + inkscape:window-y="20" + inkscape:window-maximized="1" + inkscape:current-layer="svg130" /> + <g + id="g306" + style="stroke:none;fill:url(#linearGradient1217);stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 277.5293,232.58203 c -23.98291,0 -43.5,19.51709 -43.5,43.5 0,23.98291 19.51709,43.5 43.5,43.5 23.9829,0 43.5,-19.51709 43.5,-43.5 0,-23.98291 -19.5171,-43.5 -43.5,-43.5 z m 0,7 c 20.19983,0 36.5,16.30017 36.5,36.5 0,20.19983 -16.30017,36.5 -36.5,36.5 -20.19983,0 -36.5,-16.30017 -36.5,-36.5 0,-20.19983 16.30017,-36.5 36.5,-36.5 z" + id="circle107" /> + <g + id="a" + stroke="#000000" + stroke-width="7" + transform="translate(27.528861,26.081557)" + style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 0,246.5 v 7 h 250 v -7 z" + id="path109" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z" + id="path111" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z" + id="path113" /> + </g> + <g + id="use116" + stroke="#000000" + stroke-width="7" + transform="rotate(45,232.28122,296.27106)" + style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 0,246.5 v 7 h 250 v -7 z" + id="path985" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z" + id="path987" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z" + id="path989" /> + </g> + <g + id="use118" + stroke="#000000" + stroke-width="7" + transform="rotate(90,250.72365,276.80521)" + style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 0,246.5 v 7 h 250 v -7 z" + id="path993" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z" + id="path995" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z" + id="path997" /> + </g> + <g + id="use120" + stroke="#000000" + stroke-width="7" + transform="rotate(135,258.36277,268.74219)" + style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 0,246.5 v 7 h 250 v -7 z" + id="path1001" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z" + id="path1003" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z" + id="path1005" /> + </g> + <g + id="use122" + stroke="#000000" + stroke-width="7" + transform="rotate(180,263.76443,263.04078)" + style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 0,246.5 v 7 h 250 v -7 z" + id="path1009" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z" + id="path1011" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z" + id="path1013" /> + </g> + <g + id="use124" + stroke="#000000" + stroke-width="7" + transform="rotate(-45,295.24766,229.81051)" + style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 0,246.5 v 7 h 250 v -7 z" + id="path1017" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z" + id="path1019" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z" + id="path1021" /> + </g> + <g + id="use126" + stroke="#000000" + stroke-width="7" + transform="rotate(-90,276.80521,249.27635)" + style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 0,246.5 v 7 h 250 v -7 z" + id="path1025" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z" + id="path1027" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z" + id="path1029" /> + </g> + <g + id="use128" + stroke="#000000" + stroke-width="7" + transform="rotate(-135,269.16611,257.33936)" + style="stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill:url(#linearGradient1217);fill-opacity:1;stroke-width:6;stroke-dasharray:none"> + <path + style="color:#000000;fill:url(#linearGradient1217);fill-opacity:1;stroke:none;stroke-width:6;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers" + d="m 0,246.5 2.8284271,7 250.0000029,0 v -7 z" + id="path1033" + sodipodi:nodetypes="ccccc" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 5,196.5 v 7 c 14.027764,0 24.110114,5.67622 31.017578,14.31055 C 42.925042,226.44488 46.5,238.20001 46.5,250 c 0,11.79999 -3.574958,23.55512 -10.482422,32.18945 C 29.110114,290.82378 19.027764,296.5 5,296.5 v 7 c 15.972206,0 28.389901,-6.8238 36.482422,-16.93945 C 49.574943,276.4449 53.5,263.19999 53.5,250 53.5,236.80001 49.574943,223.5551 41.482422,213.43945 33.389901,203.3238 20.972206,196.5 5,196.5 Z" + id="path1035" /> + <path + style="color:#000000;fill:url(#linearGradient1217);stroke:none;stroke-opacity:1;paint-order:stroke fill markers;fill-opacity:1;stroke-width:6;stroke-dasharray:none" + d="m 96.5,215 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z m 25,0 v 70 h 7 v -70 z" + id="path1037" /> + </g> + </g> +</svg> diff --git a/Makefile b/Makefile @@ -0,0 +1,3 @@ + +dist: + rsync -avzP ./ charon:public/runes/ diff --git a/index.html b/index.html @@ -0,0 +1,30 @@ + +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <title>CLN Rune Workshop</title> + <link rel="stylesheet" href="style.css" /> + </head> + <body> + <div id="container"> + <header> + <img width="140px" height="140px" src="AegishjalmrRed.svg" > + <div> + <h1>Rune Workshop</h1> + <h3>Craft CoreLN Authentication Runes</h3> + </div> + </header> + <section id="rune"> + <h2>Command</h2> + <textarea id="command"></textarea> + </section> + <section id="workshop"> + </section> + </div> + </body> + <script src="rune-workshop.js?v=2" ></script> +</html> + diff --git a/rune-workshop.js b/rune-workshop.js @@ -0,0 +1,372 @@ + +let STATE = {} + +async function go() { + const el = document.querySelector("#workshop") + + el.innerHTML = await render_workshop() + + load_selected() + + setInterval(try_update_command, 10000) +} + +function now_unix() { + return Math.floor(new Date().getTime() / 1000) +} + +function try_update_command() { + let r = STATE.restrictions + if (r && r.duration) { + let updated = now_unix() + r.duration + if (updated != r.time) { + r.time = updated + update_command(STATE.restrictions) + } + } +} + +function get_rpcs() { + return fetch("schemas.json").then(res => res.json()) +} + +function load_selected() { + //const method = window.location.hash.substr(1) || "commando" + + //select_method(method) +} + +function duration_scale_multiplier(v) { + switch (v) { + case "minutes": return 60 + case "hours": return 60*60 + case "days": return 60*60*24 + case "weeks": return 60*60*24*7 + case "months": return 60*60*24*30 + case "years": return 60*60*24*365 + } + + return 0 +} + +function change_duration() { + const value = document.querySelector("#duration-input").value + const scale = document.querySelector("#duration-scale").value + const mod = duration_scale_multiplier(scale) + + let r = STATE.restrictions = STATE.restrictions || {} + + if (value) { + r.duration = mod * value + r.time = (Math.floor(new Date().getTime() / 1000)) + r.duration + } else { + delete r.time + delete r.duration + } + + update_command(r) +} + +function render_time_restriction() +{ + return ` + <span class="param-name">Duration</span> + <input type="number" onkeyup="change_duration()" id="duration-input"></input> + <select onchange="change_duration()" id="duration-scale"> + <option value=minutes>Minutes</option> + <option value=hours>Hours</option> + <option value=days>Days</option> + <option value=weeks>Weeks</option> + <option value=months>Months</option> + <option value=years>Years</option> + </select> + ` +} + +function render_rate_restriction() +{ + return ` + <span class="param-name">Rate</span> + <input type="number" onkeyup="change_rate(this)" id="rate-input"></input> + Requests Per Minute + ` +} + +function change_rate(el) { + const r = STATE.restrictions = STATE.restrictions || {} + + r.rate = el.value + + update_command(r) +} + +function render_generic_restrictions_section(rpcs) +{ + return ` + <h2>Restrictions</h2> + <div> + ${render_time_restriction()} + </div> + <div> + ${render_rate_restriction()} + </div> + <div> + <span class="param-name">Method</span> + ${render_method_selector(rpcs)} + </div> + ` +} + +async function render_workshop() { + const rpcs = await get_rpcs() + STATE.rpcs = rpcs + + return ` + ${render_generic_restrictions_section(rpcs)} + <div id="method"> + </div> + ` +} + +function select_method(sel) { + const method = sel.value + const el = document.querySelector("#method") + STATE.restrictions = STATE.restrictions || {} + STATE.restrictions.params = {} + + if (method) { + let rpc = STATE.rpcs[method] + rpc.method = method + update_restriction({method}) + el.innerHTML = render_rpc(rpc) + } else { + update_command(STATE.restrictions) + el.innerHTML = "" + } + +} + +function render_rpc(rpc) { + const params = render_params(rpc) + + return ` + <h2>${rpc.method} parameters</h2> + + ${params} + + <pre>${JSON.stringify(rpc,null,4)}</pre> + ` +} + +function render_params(rpc) { + const required = rpc.required.reduce((obj, param) => { + obj[param] = true + return obj + }, {}) + + const params = Object.keys(rpc.properties) + + return params.map(p => render_param(required, rpc, p)).join("\n") +} + +function render_type(p) +{ + let type = p.type; + if (p.type === "array" && p.items) { + type = `[${p.items.type}]` + } + return `<span class="badge type-${p.type}">${type}</span>` +} + +function get_description(p) +{ + if (p.oneOf) { + return p.oneOf.map(o => o.description).filter(d => d).join("<br/><br/>") + } + + return p.description; +} + +/* + * 58 object + * 54 string + * 22 array + * 21 u32 + * 18 pubkey + * 15 msat + * 13 u64 + * 11 hex + * 11 boolean + * 10 u16 + * 7 short_channel_id + * 6 number + * 6 hash + * 6 feerate + * 4 outpoint + * 3 txid + * 3 secret + * 3 integer + * 2 msat_or_all + * 1 short_channel_id_dir + * 1 outputdesc + * 1 msat_or_any + * 1 hexstr + * 1 addresstype + */ +function get_type(p) { + // TODO: oneOf stuff + return p.type +} + +function get_input_type(type) { + switch (type) { + case "u16": + case "number": + case "u32": + case "u64": return "number" + + case "string": return "text" + default: return "text" + } +} + +function render_type_options(type) +{ + if (type === 'number') { + return ` + <option value="=">Equals</option> + <option value=">">Greater Than</option> + <option value="<">Less Than</option> + ` + } + + return ` + <option value="=">Equals</option> + <option value="^">Starts With</option> + ` +} + +function update_restriction(data) +{ + let r = STATE.restrictions = STATE.restrictions || {} + r = r.params = r.params || {} + + let v = r[data.method] = r[data.method] || {} + + if (data.param_name) { + const selkey = selector_key(data.method, data.param_name) + const value = document.querySelector(`#${selkey}-input`).value + const op = document.querySelector(`#${selkey}`).value + v[data.param_name] = {value,op} + if (value === "") { + delete v[data.param_name] + } + } + + update_command(STATE.restrictions) +} + +function update_command(r) +{ + const command_el = document.querySelector("#command") + command_el.value = build_command(r) +} + +function restriction(v, old=true) { + if (old) { + return v + } else { + return [v] + } +} + +function build_command(r) +{ + let rs = [] + if (r.params) { + for (const method of Object.keys(r.params)) { + rs.push(restriction(`method=${method}`)) + + for (const pname of Object.keys(r.params[method])) { + const {value, op} = r.params[method][pname] + rs.push(restriction(`pname${pname}${op}${value}`)) + } + } + } + + if (r.rate) { + rs.push(restriction(`rate=${r.rate}`)) + } + + if (r.time) { + rs.push(restriction(`time<${r.time}`)) + } + + const out = JSON.stringify(rs) + + return `lightning-cli commando-rune restrictions='${out}'` +} + +function selector_key(method, param_name) +{ + return method + param_name +} + +function render_restriction_tool(rpc, param_name, param) +{ + const type = get_type(param) || "string" + const input_type = get_input_type(type) + + const method = rpc.method + const json_p = JSON.stringify({ method, param_name, param }) + const selkey = selector_key(method, param_name) + const updater = `update_restriction(${json_p})` + + return ` + <div class="restriction-tool"> + <select onchange='${updater}' id="${selkey}"> + ${render_type_options(input_type)} + </select> + <input id='${selkey}-input' onkeyup='${updater}' type="${input_type}"></input> + </div> + ` +} + +function render_param(required, rpc, param) { + const p = rpc.properties[param] + + const is_req = !!required[param] + const req = is_req ? "param-required" : "" + const desc = get_description(p) + const typ = get_type(p) + + return ` + <span class="param-name ${req}">${param}</span> + ${render_type(p)} + <!-- + <span class="required">${is_req? "required" : ""}</span> + --> + <blockquote> + ${desc} + ${render_restriction_tool(rpc, param, p)} + </blockquote> + ` +} + +function render_method_selector(rpcs) { + let methods = Object.keys(rpcs) + methods.unshift("") + + const options = methods.map(method => + `<option id="${method}" value="${method}">${method}</option>`) + .join("\n") + + return ` + <select id="method_selector" onchange="select_method(this)"> + ${options} + </select> + ` +} + + +go() diff --git a/schemas.json b/schemas.json @@ -0,0 +1 @@ +{"addgossip": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["message"], "properties": {"message": {"type": "hex", "description": "The raw, hex-encoded, gossip message to add to the local gossip view."}}}, "autocleaninvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"expired_by": {"type": "u64", "description": "How long an invoice must be expired (seconds) before we delete it."}, "cycle_seconds": {"type": "u64", "description": "The interval (in seconds) between cleaning expired invoices"}}}, "checkmessage": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["message", "zbase"], "properties": {"message": {"type": "string", "description": "Message to be checked against the signature."}, "zbase": {"type": "string", "description": "The Zbase32 encoded signature to verify."}, "pubkey": {"type": "pubkey", "description": "The Zbase32 encoded signature to verify."}}}, "close": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["id"], "properties": {"id": {"type": "string", "description": "peer id, channel id or short_channel_id"}, "unilateraltimeout": {"type": "u32", "description": ""}, "destination": {"type": "string", "description": ""}, "fee_negotiation_step": {"type": "string", "description": ""}, "wrong_funding": {"type": "txid", "description": ""}, "force_lease_closed": {"type": "boolean", "description": ""}, "feerange": {"type": "array", "items": {"type": "feerate"}, "description": ""}}}, "commando": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["peer_id", "method"], "properties": {"peer_id": {"type": "pubkey", "description": "peer to command"}, "method": {"type": "string", "description": "method to invoke on peer"}, "params": {"oneOf": [{"type": "array", "description": "array of positional parameters"}, {"type": "object", "description": "parameters for method"}]}, "rune": {"type": "string", "description": "rune to authorize the command"}}}, "commando-rune": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"rune": {"type": "string", "description": "optional rune to add to"}, "restrictions": {"oneOf": [{"type": "array", "description": "array of restrictions to add to rune", "items": {"type": "string"}}, {"type": "string", "description": "single restrictions to add to rune, or readonly."}]}}}, "connect": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["id"], "properties": {"id": {"type": "string", "description": ""}, "host": {"type": "string", "description": "The hostname of the node."}, "port": {"type": "u16", "description": "Port to try connecting to"}}}, "createinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["invstring", "label", "preimage"], "properties": {"invstring": {"type": "string", "description": ""}, "label": {"type": "string", "description": ""}, "preimage": {"type": "hex", "description": ""}}}, "createonion": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["hops", "assocdata"], "properties": {"hops": {"type": "array", "description": "", "items": {"type": "object", "additionalProperties": false, "required": ["pubkey", "payload"], "properties": {"pubkey": {"type": "pubkey"}, "payload": {"type": "hex"}}}}, "assocdata": {"type": "hex", "description": ""}, "session_key": {"type": "secret"}, "onion_size": {"type": "u16"}}}, "datastore": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["key"], "properties": {"key": {"oneOf": [{"type": "array", "description": "key is an array of values (though a single value is treated as a one-element array), to form a heirarchy. Using the first element of the key as the plugin name (e.g. [ 'summary' ]) is recommended. A key can either have children or a value, never both: parents are created and removed automatically.", "items": {"type": "string"}}, {"type": "string"}]}, "string": {"type": "string", "description": ""}, "hex": {"type": "hex", "description": ""}, "mode": {"type": "string", "enum": ["must-create", "must-replace", "create-or-replace", "must-append", "create-or-append"], "description": ""}, "generation": {"type": "u64", "description": "If specified, means that the update will fail if the previously-existing data is not exactly that generation. This allows for simple atomicity. This is only legal with mode \u201cmust-replace\u201d or \u201cmust-append\u201d."}}}, "deldatastore": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["key"], "properties": {"key": {"oneOf": [{"type": "array", "description": "key is an array of values (though a single value is treated as a one-element array), to form a heirarchy. Using the first element of the key as the plugin name (e.g. [ 'summary' ]) is recommended. A key can either have children or a value, never both: parents are created and removed automatically.", "items": {"type": "string"}}, {"type": "string"}]}, "generation": {"type": "u64", "description": "If specified, means that the update will fail if the previously-existing data is not exactly that generation. This allows for simple atomicity. This is only legal with mode \u201cmust-replace\u201d or \u201cmust-append\u201d."}}}, "delexpiredinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"maxexpirytime": {"type": "u64", "description": ""}}}, "delinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["label", "status"], "properties": {"label": {"oneOf": [{"type": "string", "description": ""}, {"type": "integer", "description": ""}]}, "status": {"type": "string", "enum": ["paid", "expired", "unpaid"]}, "desconly": {"type": "boolean"}}}, "disconnect": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["id"], "properties": {"id": {"type": "pubkey"}, "force": {"type": "boolean"}}}, "emergencyrecover": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {}}, "feerates": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["style"], "properties": {"style": {"type": "string", "enum": ["perkb", "perkw"]}}}, "fundchannel": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["id", "amount"], "properties": {"id": {"type": "pubkey", "description": "id is the peer id obtained from connect."}, "amount": {"type": "msat_or_all"}, "feerate": {"type": "feerate"}, "announce": {"type": "boolean"}, "minconf": {"type": "u32"}, "push_msat": {"type": "msat"}, "close_to": {"type": "string"}, "request_amt": {"type": "msat"}, "compact_lease": {"type": "string"}, "utxos": {"type": "array", "items": {"type": "outpoint"}}, "mindepth": {"description": "Number of confirmations required before we consider the channel active", "type": "u32"}}}, "fundpsbt": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["satoshi", "feerate", "startweight"], "properties": {"satoshi": {"type": "msat"}, "feerate": {"type": "feerate"}, "startweight": {"type": "u32"}, "minconf": {"type": "u32"}, "reserve": {"type": "u32", "description": "reserve is a number: if non-zero number then reserveinputs is called (successfully, with exclusive true) on the returned PSBT for this number of blocks (default: 72)."}, "locktime": {"type": "u32"}, "min_witness_weight": {"type": "u32"}, "excess_as_change": {"type": "boolean"}}}, "getinfo": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {}}, "getroute": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["id", "amount_msat", "riskfactor"], "properties": {"id": {"type": "pubkey", "description": ""}, "amount_msat": {"type": "msat", "description": ""}, "riskfactor": {"type": "u64", "description": ""}, "cltv": {"type": "number", "description": ""}, "fromid": {"type": "pubkey", "description": ""}, "fuzzpercent": {"type": "u32", "description": ""}, "exclude": {"type": "array", "description": "", "items": {"type": "string"}}, "maxhops": {"type": "u32", "description": ""}}}, "invoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["amount_msat", "label", "description"], "properties": {"amount_msat": {"type": "msat_or_any", "description": ""}, "description": {"type": "string", "description": ""}, "label": {"oneOf": [{"type": "string", "description": ""}, {"type": "integer", "description": ""}]}, "expiry": {"type": "u64", "description": ""}, "fallbacks": {"type": "array", "description": "", "items": {"type": "string"}}, "preimage": {"type": "hex", "description": ""}, "exposeprivatechannels": {"oneOf": [{"type": "boolean", "description": ""}, {"type": "array", "items": {"type": "short_channel_id"}}, {"type": "short_channel_id"}]}, "cltv": {"type": "u32", "description": ""}, "deschashonly": {"type": "boolean", "description": ""}}}, "keysend": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["destination", "amount_msat"], "properties": {"destination": {"type": "pubkey"}, "amount_msat": {"type": "msat"}, "label": {"type": "string"}, "maxfeepercent": {"type": "number"}, "retry_for": {"type": "u32"}, "maxdelay": {"type": "u32"}, "exemptfee": {"type": "msat"}, "routehints": {"type": "array", "items": {"type": "array", "items": {"type": "object", "additionalProperties": false, "required": ["id", "scid", "feebase", "feeprop", "expirydelta"], "properties": {"id": {"type": "pubkey"}, "scid": {"type": "short_channel_id"}, "feebase": {"type": "msat"}, "feeprop": {"type": "u32"}, "expirydelta": {"type": "u16"}}}}}, "extratlvs": {"type": "object", "additionalProperties": true, "required": []}}}, "listchannels": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"short_channel_id": {"type": "short_channel_id", "description": "If short_channel_id is a short channel id, then only known channels with a matching short_channel_id are returned. Otherwise, it must be null."}, "source": {"type": "pubkey", "description": "If source is a node id, then only channels leading from that node id are returned."}, "destination": {"type": "pubkey", "description": "If destination is a node id, then only channels leading to that node id are returned."}}}, "listdatastore": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"key": {"oneOf": [{"type": "array", "description": "key is an array of values (though a single value is treated as a one-element array), to form a heirarchy. Using the first element of the key as the plugin name (e.g. [ 'summary' ]) is recommended. A key can either have children or a value, never both: parents are created and removed automatically.", "items": {"type": "string"}}, {"type": "string", "description": ""}]}}}, "listforwards": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "properties": {"status": {"type": "string", "enum": ["offered", "settled", "local_failed", "failed"]}, "in_channel": {"type": "short_channel_id"}, "out_channel": {"type": "short_channel_id"}}}, "listfunds": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"spent": {"type": "boolean", "description": "Should outputs that are already spent be included in the result?"}}}, "listinvoices": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"label": {"oneOf": [{"type": "string", "description": ""}, {"type": "integer", "description": ""}]}, "invstring": {"type": "string", "description": ""}, "payment_hash": {"type": "hex", "description": ""}, "offer_id": {"type": "string", "description": ""}}}, "listnodes": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"id": {"type": "pubkey"}}}, "listpays": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"bolt11": {"type": "string"}, "payment_hash": {"type": "hash"}, "status": {"type": "string", "enum": ["pending", "complete", "failed"]}}}, "listpeers": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"id": {"type": "pubkey", "description": "If supplied, limits the result to just the peer with the given ID, if it exists."}, "level": {"type": "string", "description": "Supplying level will show log entries related to that peer at the given log level. Valid log levels are \u201cio\u201d, \u201cdebug\u201d, \u201cinfo\u201d, and \u201cunusual\u201d."}}}, "listsendpays": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"bolt11": {"type": "string"}, "payment_hash": {"type": "hash"}, "status": {"type": "string", "enum": ["pending", "complete", "failed"]}}}, "listtransactions": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {}}, "makesecret": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["hex"], "properties": {"hex": {"type": "hex", "description": "This will be used for deriving the secret"}}}, "newaddr": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {"addresstype": {"type": "string", "enum": ["bech32", "p2sh-segwit", "all"]}}}, "pay": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["bolt11"], "properties": {"bolt11": {"type": "string"}, "amount_msat": {"type": "msat"}, "label": {"type": "string"}, "riskfactor": {"type": "number"}, "maxfeepercent": {"type": "number"}, "retry_for": {"type": "u16"}, "maxdelay": {"type": "u16"}, "exemptfee": {"type": "msat"}, "localofferid": {"type": "hex"}, "exclude": {"type": "array", "items": {"oneOf": [{"type": "short_channel_id_dir"}, {"type": "pubkey"}]}}, "maxfee": {"type": "msat"}, "description": {"type": "string"}}}, "ping": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["id"], "additionalProperties": false, "properties": {"id": {"type": "pubkey"}, "len": {"type": "number"}, "pongbytes": {"type": "number"}}}, "recoverchannel": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["scb"], "scb": {"type": "array", "description": "SCB of the channels in an array", "items": {"type": "hexstr"}}}, "sendonion": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["onion", "first_hop", "payment_hash"], "properties": {"onion": {"type": "hex"}, "first_hop": {"type": "object", "required": ["id", "amount_msat", "delay"], "properties": {"id": {"type": "pubkey"}, "amount_msat": {"type": "msat"}, "delay": {"type": "u16"}}}, "payment_hash": {"type": "hash"}, "label": {"type": "string"}, "shared_secrets": {"type": "array", "items": {"type": "secret"}}, "partid": {"type": "u16"}, "bolt11": {"type": "string"}, "amount_msat": {"type": "msat"}, "destination": {"type": "pubkey"}, "localofferid": {"type": "hash"}, "groupid": {"type": "u64"}}}, "sendpay": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["route", "payment_hash"], "properties": {"route": {"type": "array", "items": {"type": "object", "required": ["amount_msat", "id", "delay", "channel"], "properties": {"amount_msat": {"type": "msat"}, "msatoshi": {"deprecated": "true"}, "id": {"type": "pubkey"}, "delay": {"type": "u16"}, "channel": {"type": "short_channel_id"}}}}, "payment_hash": {"type": "hash"}, "label": {"type": "string"}, "amount_msat": {"type": "msat"}, "bolt11": {"type": "string"}, "payment_secret": {"type": "secret"}, "partid": {"type": "u16"}, "localofferid": {"type": "hex"}, "groupid": {"type": "u64"}}}, "sendpsbt": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["psbt"], "properties": {"psbt": {"type": "string"}, "reserve": {"type": "boolean"}}}, "signmessage": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": ["message"], "additionalProperties": false, "properties": {"message": {"type": "string"}}}, "signpsbt": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["psbt"], "properties": {"psbt": {"type": "string"}, "signonly": {"type": "array", "items": {"type": "u32"}}}}, "staticbackup": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "required": [], "additionalProperties": false, "properties": {}}, "stop": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {}}, "txdiscard": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["txid"], "properties": {"txid": {"type": "txid"}}}, "txprepare": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["outputs"], "properties": {"outputs": {"type": "array", "items": {"type": "outputdesc"}}, "feerate": {"type": "feerate"}, "minconf": {"type": "u32"}, "utxos": {"type": "array", "items": {"type": "outpoint"}}}}, "txsend": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["txid"], "properties": {"txid": {"type": "txid"}}}, "utxopsbt": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["satoshi", "feerate", "startweight", "utxos"], "properties": {"satoshi": {"type": "msat"}, "feerate": {"type": "feerate"}, "startweight": {"type": "u32"}, "utxos": {"type": "array", "items": {"type": "outpoint"}}, "reserve": {"type": "u32", "description": "reserve is a number: if non-zero number then reserveinputs is called (successfully, with exclusive true) on the returned PSBT for this number of blocks (default: 72)."}, "reservedok": {"type": "boolean"}, "locktime": {"type": "u32"}, "min_witness_weight": {"type": "u32"}, "excess_as_change": {"type": "boolean"}}}, "waitanyinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": [], "properties": {"lastpay_index": {"type": "u64"}, "timeout": {"type": "u64"}}}, "waitinvoice": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["label"], "properties": {"label": {"type": "string"}}}, "waitsendpay": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["payment_hash"], "properties": {"payment_hash": {"type": "hash"}, "timeout": {"type": "u32"}, "partid": {"type": "u64"}, "groupid": {"type": "u64"}}}, "withdraw": {"$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "additionalProperties": false, "required": ["destination"], "properties": {"destination": {"type": "string"}, "satoshi": {"type": "msat_or_all"}, "feerate": {"type": "feerate"}, "minconf": {"type": "u16"}, "utxos": {"type": "array", "items": {"type": "outpoint"}}}}}+ \ No newline at end of file diff --git a/style.css b/style.css @@ -0,0 +1,94 @@ + +body { + background-color: #333; + color: #ddd; + font-family: -apple-system, -system-ui, sans-serif; +} + +select { + cursor: pointer; + padding: 6px; + border-radius: 8px; + + background-color: #666; + margin: 20px 0 20px 0; +} + +.param-name { + color: white; +} + +.badge { + font-size: 0.7em; + padding: 3px; + background-color: #666; + color: white; + border-radius: 5px; +} + +.param-required { + font-weight: bold; +} + +.type-required { + background-color: #BE72CE; +} + +.required { + font-size: 0.6em; + color: #888; +} + +header { + margin-bottom: 20px; +} + +#command { + width: 100%; + height: 50px; +} + +.type-string { + background-color: #006400; +} + + +option { + color: white; +} + +header { + display: flex; + align-items: center; +} + +#container { + margin: auto; + max-width: 800px; +} + +@media (min-width: 400px) +.container { + width: 85%; + padding: 0; +} + +h1,h3{ + margin: 0; +} + +h2 { + margin: 20px 0 20px 0; +} + +h1 { + color: #FF7D06; +} + +h2,h3 { + color: #FFB906; +} + +header > img { + margin-right: 20px; +} diff --git a/sync-schemas.xonsh b/sync-schemas.xonsh @@ -0,0 +1,26 @@ +#!/usr/bin/env xonsh + +import os +import json +import sys + +# fetch latest +rm -rf lightning-master +curl -sL https://github.com/ElementsProject/lightning/archive/master.tar.gz > lightning.tar.gz +tar xf lightning.tar.gz + +schemas = $(ls -1 lightning-master/doc/schemas/*.request.json).strip().split("\n") + +out = {} +for schema in schemas: + filename = os.path.basename(schema) + [method,_,_] = filename.split(".") + with open(schema) as f: + content = "".join(f.readlines()) + out[method] = json.loads(content) + + +print("Writing schemas.json", file=sys.stderr) + +with open("schemas.json", "w") as f: + f.write(json.dumps(out))