diff options
Diffstat (limited to 'packages')
20 files changed, 437 insertions, 40 deletions
diff --git a/packages/anastasis-webui/clean_and_build.sh b/packages/anastasis-webui/clean_and_build.sh index 300ed8930..2fa3ec777 100755 --- a/packages/anastasis-webui/clean_and_build.sh +++ b/packages/anastasis-webui/clean_and_build.sh @@ -10,16 +10,51 @@ cp \ src/scss/fonts/materialdesignicons-webfont-4.9.95.woff2 \ dist/fonts -echo css -pnpm exec sass -I . ./src/scss/main.scss dist/main.css & -echo js -pnpm exec esbuild --log-level=error --bundle src/main.ts --outdir=dist --target=es6 --loader:.svg=dataurl --format=iife --sourcemap --jsx-factory=h --jsx-fragment=Fragment --platform=browser & +function build_css() { + pnpm exec sass -I . ./src/scss/main.scss dist/main.css +} +function build_js() { + pnpm exec esbuild --log-level=error --bundle $1 --outdir=dist --target=es6 --loader:.svg=dataurl --format=iife --sourcemap --jsx-factory=h --jsx-fragment=Fragment --platform=browser +} + +function bundle() { + cat html/$1.html \ + | sed -e '/ANASTASIS_SCRIPT_CONTENT/ {' -e 'r dist/main.js' -e 'd' -e '}' \ + | sed -e '/ANASTASIS_STYLE_CONTENT/ {' -e 'r dist/main.css' -e 'd' -e '}' \ + >dist/$1.html +} + +function cleanup { + trap - SIGHUP SIGINT SIGTERM SIGQUIT + echo -n "Cleaning up... " + kill -- -$$ + exit 1 +} +trap cleanup SIGHUP SIGINT SIGTERM SIGQUIT + + +echo compile +build_css & +build_js src/main.ts & +build_js src/main.test.ts & wait -n wait -n +wait -n +pnpm run --silent test -- -R dot echo html -cat ui.html \ - | sed -e '/ANASTASIS_SCRIPT_CONTENT/ {' -e 'r dist/main.js' -e 'd' -e '}' \ - | sed -e '/ANASTASIS_STYLE_CONTENT/ {' -e 'r dist/main.css' -e 'd' -e '}' \ - >dist/index.html -echo done +bundle ui +bundle ui-dev + + +if [ "WATCH" == "$1" ]; then + + echo watch mode + inotifywait -e close_write -r src -q -m | while read line; do + DATE=$(date) + echo $DATE $line + build_js src/main.ts + bundle ui-dev + ./watch/send_reload.sh + done; +fi diff --git a/packages/anastasis-webui/dev.mjs b/packages/anastasis-webui/dev.mjs index d6b6bf10d..3f4915ffc 100755 --- a/packages/anastasis-webui/dev.mjs +++ b/packages/anastasis-webui/dev.mjs @@ -1,4 +1,19 @@ #!/usr/bin/env node +/* + This file is part of GNU Anastasis + (C) 2021-2022 Anastasis SARL + + GNU Anastasis is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ /* eslint-disable no-undef */ import esbuild from 'esbuild' import fs from 'fs'; @@ -41,14 +56,17 @@ const watcher = chokidar broadcast(file, { type: "RELOAD" }); }); - -fs.writeFileSync("dist/stories.html", fs.readFileSync("stories.html")) +/** + * Just bundling UI Stories. + * FIXME: add linaria CSS after implementing Material so CSS will be bundled + */ +fs.writeFileSync("dist/index.html", fs.readFileSync("html/stories.html")) fs.writeFileSync("dist/mocha.css", fs.readFileSync("node_modules/mocha/mocha.css")) fs.writeFileSync("dist/mocha.js", fs.readFileSync("node_modules/mocha/mocha.js")) fs.writeFileSync("dist/mocha.js.map", fs.readFileSync("node_modules/mocha/mocha.js.map")) export const buildConfig = { - entryPoints: ['src/stories.tsx'], + entryPoints: ['src/main.ts', 'src/stories.tsx'], bundle: true, outdir: 'dist', minify: false, @@ -75,7 +93,6 @@ const server = await esbuild }); console.log(`Dev server is ready at http://localhost:${server.port}/. -http://localhost:${server.port}/stories.html for the components stories. The server is running a using websocket at ${devServerPort} to notify code change and live reload. `); diff --git a/packages/anastasis-webui/stories.html b/packages/anastasis-webui/html/stories.html index 9f41fdeaf..9f41fdeaf 100644 --- a/packages/anastasis-webui/stories.html +++ b/packages/anastasis-webui/html/stories.html diff --git a/packages/anastasis-webui/html/ui-dev.html b/packages/anastasis-webui/html/ui-dev.html new file mode 100644 index 000000000..4cc36268e --- /dev/null +++ b/packages/anastasis-webui/html/ui-dev.html @@ -0,0 +1,50 @@ +<!DOCTYPE html> +<html + lang="en" + class="has-aside-left has-aside-mobile-transition has-navbar-fixed-top has-aside-expanded" +> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width,initial-scale=1" /> + <meta name="mobile-web-app-capable" content="yes" /> + <meta name="apple-mobile-web-app-capable" content="yes" /> + + <link + rel="icon" + href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn3//3ryn/795Tf/WrpP/2LCW/8B6T//w4Nb///////Pn4P+/d0v/9u3n/+7d0v/EhV7//v///+HDr//fxLD/zph2/+TJt//8/Pv/woBX//Lm3f/y5dz/v3hN//bu6f/JjGn/4sW0///////Df1j/8OLZ//v6+P+/elH/+vj1//jy7f+/elL//////+zYzP/Eg13//////967p//MlHT/wn5X///////v4Nb/yY1s///////jw7H/06KG////////////z5t9/+fNvf//////x4pn//Pp4v/8+vn/w39X/8WEX///////5s/A/9CbfP//////27Oc/9y2n////////////9itlf/gu6f//////86Vdf/r2Mz//////8SCXP/Df1j//////+7d0v/KkG7//////+HBrf/VpYr////////////RnoH/5sq6///////Ii2n/8ubf//39/P/Cf1j/xohk/+bNvv//////wn5W//Tq4//58/D/wHxV//7+/f/59fH/v3xU//39/P/w4Nf/xIFb///////hw7H/yo9t/+/f1f/AeU3/+/n2/+nSxP/FhmD//////9qzm//Upon/4MSx/96+qf//////xINc/+3bz//48e3/v3hN//Pn3///////6M+//752S//gw6//06aK/8J+VP/kzLr/zZd1/8OCWv/q18r/17KZ/9Ooi//fv6r/v3dK/+vWyP///////v39///////27un/1aeK/9Opjv/m1cf/1KCC/9a0nP/n08T/0Jx8/82YdP/QnHz/16yR//jx7P///////v39///////+/f3///7+///////+//7//v7+///////+/v7//v/+/////////////////////////v7//v79///////////////////+/v/+/Pv//v39///+/v/+/Pv///7+//7+/f/+/Pv//v39//79/P/+/Pv///7+////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" + /> + <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" /> + <style type="text/css"> + /* <![CDATA[ */ + ANASTASIS_STYLE_CONTENT + /* <![CDATA[ */ + </style> + </head> + + <body> + <div id="container" class="anastasis-container"></div> + <script type="application/javascript"> + ANASTASIS_SCRIPT_CONTENT; + </script> + <script type="application/javascript"> + function setupLiveReload(port) { + const socketPath = `ws://localhost:${port}/socket`; + + const ws = new WebSocket(socketPath); + ws.onmessage = (message) => { + const event = JSON.parse(message.data); + if (event.type === "LOG") { + console.log(event.message); + } + if (event.type === "RELOAD") { + window.location.reload(); + } + }; + ws.onerror = (error) => { + console.error(error); + }; + } + setupLiveReload(8003); + </script> + </body> +</html> diff --git a/packages/anastasis-webui/ui.html b/packages/anastasis-webui/html/ui.html index 17c48e904..17c48e904 100644 --- a/packages/anastasis-webui/ui.html +++ b/packages/anastasis-webui/html/ui.html diff --git a/packages/anastasis-webui/package.json b/packages/anastasis-webui/package.json index 95b85585d..7c57160ce 100644 --- a/packages/anastasis-webui/package.json +++ b/packages/anastasis-webui/package.json @@ -9,7 +9,7 @@ "dev": "./dev.mjs", "prepare": "pnpm compile", "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'", - "test": "echo no tests", + "test": "mocha --enable-source-maps 'dist/**/*.test.js'", "pretty": "prettier --write src" }, "dependencies": { @@ -18,6 +18,7 @@ "date-fns": "2.28.0", "jed": "1.1.1", "preact": "^10.5.15", + "preact-render-to-string": "^5.1.19", "preact-router": "^3.2.1", "qrcode-generator": "^1.4.4" }, @@ -34,6 +35,7 @@ }, "devDependencies": { "@creativebulma/bulma-tooltip": "^1.2.0", + "@types/mocha": "^9.0.0", "bulma": "^0.9.3", "bulma-checkbox": "^1.1.1", "bulma-radio": "^1.1.1", diff --git a/packages/anastasis-webui/src/main.test.ts b/packages/anastasis-webui/src/main.test.ts new file mode 100644 index 000000000..e65cca454 --- /dev/null +++ b/packages/anastasis-webui/src/main.test.ts @@ -0,0 +1,48 @@ +/* + This file is part of GNU Anastasis + (C) 2021-2022 Anastasis SARL + + GNU Anastasis is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ +import { setupI18n } from "@gnu-taler/taler-util"; +import { renderNodeOrBrowser } from "./test-utils.js"; +import * as pages from "./pages/home/index.storiesNo.js"; + +setupI18n("en", { en: {} }); + +function testThisStory(st: any): any { + describe(`render examples for ${(st as any).default.title}`, () => { + Object.keys(st).forEach((k) => { + const Component = (st as any)[k]; + if (k === "default" || !Component) return; + + it(`example: ${k}`, () => { + renderNodeOrBrowser(Component, Component.args); + }); + }); + }); +} + +describe("render every storybook example", () => { + [pages].forEach(function testAll(st: any) { + if (Array.isArray(st.default)) { + st.default.forEach(testAll); + } else { + testThisStory(st); + } + }); +}); diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx index feeac274d..d4675f9da 100644 --- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx @@ -223,7 +223,7 @@ function TableRow({ onDelete: (s: string) => void; url: string; info: AuthenticationProviderStatusOk; -}) { +}): VNode { const [status, setStatus] = useState("checking"); useEffect(function () { testProvider(url.endsWith("/") ? url.substring(0, url.length - 1) : url) diff --git a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx index 43d865b48..534f9136d 100644 --- a/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/ContinentSelectionScreen.tsx @@ -125,13 +125,6 @@ export function ContinentSelectionScreen(): VNode { </div> </div> </div> - - {/* {theCountry && <div class="field"> - <label class="label">Available currencies:</label> - <div class="control"> - <input class="input is-small" type="text" readonly value={theCountry.currency} /> - </div> - </div>} */} </div> <div class="column is-two-third"> <p> @@ -151,18 +144,11 @@ export function ContinentSelectionScreen(): VNode { }} > <p> - If you just want to try out Anastasis, we recomment that you + If you just want to try out Anastasis, we recommend that you choose <b>Testcontinent</b> with <b>Demoland</b>. For this special country, you will be asked for a simple number and not real, personal identifiable information. </p> - {/* - <p> - Because of the diversity of personally identifying information in - different countries and cultures, we do not support all countries - yet. If you want to improve the supported countries,{" "} - <a href="mailto:contact@anastasis.lu">contact us</a>. - </p> */} </div> </div> </div> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx index f9b292d94..0285c87e1 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx @@ -36,6 +36,7 @@ export function AuthMethodTotpSetup({ const [test, setTest] = useState(""); const secretKey = useMemo(() => { const array = new Uint8Array(32); + if (typeof window === "undefined") return array; return window.crypto.getRandomValues(array); }, []); diff --git a/packages/anastasis-webui/src/stories.tsx b/packages/anastasis-webui/src/stories.tsx index a51dfb20f..351d6f37b 100644 --- a/packages/anastasis-webui/src/stories.tsx +++ b/packages/anastasis-webui/src/stories.tsx @@ -143,21 +143,24 @@ function ExampleList({ {k.examples.map((r) => { const e = encodeURIComponent; const eId = `${e(r.group)}-${e(r.component)}-${e(r.name)}`; + function doSelection(e: any): void { + e.preventDefault(); + location.hash = `#${eId}`; + onSelectStory(r, eId); + } const isSelected = selected && selected.component === r.component && selected.group === r.group && selected.name === r.name; return ( - <dd id={eId} key={r.name} data-selected={isSelected}> - <a - href={`#${eId}`} - onClick={(e) => { - e.preventDefault(); - location.hash = `#${eId}`; - onSelectStory(r, eId); - }} - > + <dd + id={eId} + key={r.name} + data-selected={isSelected} + onClick={doSelection} + > + <a href={`#${eId}`} onClick={doSelection}> {r.name} </a> </dd> diff --git a/packages/anastasis-webui/src/test-utils.ts b/packages/anastasis-webui/src/test-utils.ts new file mode 100644 index 000000000..1fcc753ee --- /dev/null +++ b/packages/anastasis-webui/src/test-utils.ts @@ -0,0 +1,201 @@ +/* + This file is part of GNU Anastasis + (C) 2021-2022 Anastasis SARL + + GNU Anastasis is free software; you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License along with + GNU Anastasis; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import { + ComponentChildren, + Fragment, + FunctionalComponent, + h as create, + options, + render as renderIntoDom, + VNode, +} from "preact"; +import { render as renderToString } from "preact-render-to-string"; + +// When doing tests we want the requestAnimationFrame to be as fast as possible. +// without this option the RAF will timeout after 100ms making the tests slower +options.requestAnimationFrame = (fn: () => void) => { + // console.log("RAF called") + return fn(); +}; + +export function createExample<Props>( + Component: FunctionalComponent<Props>, + props: Partial<Props> | (() => Partial<Props>), +): ComponentChildren { + //FIXME: props are evaluated on build time + // in some cases we want to evaluated the props on render time so we can get some relative timestamp + // check how we can build evaluatedProps in render time + const evaluatedProps = typeof props === "function" ? props() : props; + const Render = (args: any): VNode => create(Component, args); + Render.args = evaluatedProps; + return Render; +} + +export function createExampleWithCustomContext<Props, ContextProps>( + Component: FunctionalComponent<Props>, + props: Partial<Props> | (() => Partial<Props>), + ContextProvider: FunctionalComponent<ContextProps>, + contextProps: Partial<ContextProps>, +): ComponentChildren { + const evaluatedProps = typeof props === "function" ? props() : props; + const Render = (args: any): VNode => create(Component, args); + const WithContext = (args: any): VNode => + create(ContextProvider, { + ...contextProps, + children: [Render(args)], + } as any); + WithContext.args = evaluatedProps; + return WithContext; +} + +export function NullLink({ + children, +}: { + children?: ComponentChildren; +}): VNode { + return create("a", { children, href: "javascript:void(0);" }); +} + +export function renderNodeOrBrowser(Component: any, args: any): void { + const vdom = create(Component, args); + if (typeof window === "undefined") { + renderToString(vdom); + } else { + const div = document.createElement("div"); + document.body.appendChild(div); + renderIntoDom(vdom, div); + renderIntoDom(null, div); + document.body.removeChild(div); + } +} + +interface Mounted<T> { + unmount: () => void; + getLastResultOrThrow: () => T; + assertNoPendingUpdate: () => void; + waitNextUpdate: (s?: string) => Promise<void>; +} + +const isNode = typeof window === "undefined"; + +export function mountHook<T>( + callback: () => T, + Context?: ({ children }: { children: any }) => VNode, +): Mounted<T> { + // const result: { current: T | null } = { + // current: null + // } + let lastResult: T | Error | null = null; + + const listener: Array<() => void> = []; + + // component that's going to hold the hook + function Component(): VNode { + try { + lastResult = callback(); + } catch (e) { + if (e instanceof Error) { + lastResult = e; + } else { + lastResult = new Error(`mounting the hook throw an exception: ${e}`); + } + } + + // notify to everyone waiting for an update and clean the queue + listener.splice(0, listener.length).forEach((cb) => cb()); + return create(Fragment, {}); + } + + // create the vdom with context if required + const vdom = !Context + ? create(Component, {}) + : create(Context, { children: [create(Component, {})] }); + + // waiter callback + async function waitNextUpdate(_label = ""): Promise<void> { + if (_label) _label = `. label: "${_label}"`; + await new Promise((res, rej) => { + const tid = setTimeout(() => { + rej( + Error(`waiting for an update but the hook didn't make one${_label}`), + ); + }, 100); + + listener.push(() => { + clearTimeout(tid); + res(undefined); + }); + }); + } + + const customElement = {} as Element; + const parentElement = isNode ? customElement : document.createElement("div"); + if (!isNode) { + document.body.appendChild(parentElement); + } + + renderIntoDom(vdom, parentElement); + + // clean up callback + function unmount(): void { + if (!isNode) { + document.body.removeChild(parentElement); + } + } + + function getLastResult(): T | Error | null { + const copy = lastResult; + lastResult = null; + return copy; + } + + function getLastResultOrThrow(): T { + const r = getLastResult(); + if (r instanceof Error) throw r; + if (!r) throw Error("there was no last result"); + return r; + } + + async function assertNoPendingUpdate(): Promise<void> { + await new Promise((res, rej) => { + const tid = setTimeout(() => { + res(undefined); + }, 10); + + listener.push(() => { + clearTimeout(tid); + rej( + Error(`Expecting no pending result but the hook got updated. + If the update was not intended you need to check the hook dependencies + (or dependencies of the internal state) but otherwise make + sure to consume the result before ending the test.`), + ); + }); + }); + + const r = getLastResult(); + if (r) + throw Error(`There are still pending results. + This may happen because the hook did a new update but the test didn't consume the result using getLastResult`); + } + return { + unmount, + getLastResultOrThrow, + waitNextUpdate, + assertNoPendingUpdate, + }; +} diff --git a/packages/anastasis-webui/src/utils/index.tsx b/packages/anastasis-webui/src/utils/index.tsx index ce21071f7..204c48d18 100644 --- a/packages/anastasis-webui/src/utils/index.tsx +++ b/packages/anastasis-webui/src/utils/index.tsx @@ -209,10 +209,12 @@ export const reducerStatesExample = { initial: undefined, recoverySelectCountry: { ...base, + reducer_type: "recovery", recovery_state: RecoveryStates.CountrySelecting, } as ReducerState, recoverySelectContinent: { ...base, + reducer_type: "recovery", recovery_state: RecoveryStates.ContinentSelecting, } as ReducerState, secretSelection: { @@ -222,10 +224,12 @@ export const reducerStatesExample = { } as ReducerState, recoveryFinished: { ...base, + reducer_type: "recovery", recovery_state: RecoveryStates.RecoveryFinished, } as ReducerState, challengeSelecting: { ...base, + reducer_type: "recovery", recovery_state: RecoveryStates.ChallengeSelecting, } as ReducerState, challengeSolving: { @@ -235,34 +239,42 @@ export const reducerStatesExample = { } as ReducerStateRecovery, challengePaying: { ...base, + reducer_type: "recovery", recovery_state: RecoveryStates.ChallengePaying, } as ReducerState, recoveryAttributeEditing: { ...base, + reducer_type: "recovery", recovery_state: RecoveryStates.UserAttributesCollecting, } as ReducerState, backupSelectCountry: { ...base, + reducer_type: "backup", backup_state: BackupStates.CountrySelecting, } as ReducerState, backupSelectContinent: { ...base, + reducer_type: "backup", backup_state: BackupStates.ContinentSelecting, } as ReducerState, secretEdition: { ...base, + reducer_type: "backup", backup_state: BackupStates.SecretEditing, } as ReducerState, policyReview: { ...base, + reducer_type: "backup", backup_state: BackupStates.PoliciesReviewing, } as ReducerState, policyPay: { ...base, + reducer_type: "backup", backup_state: BackupStates.PoliciesPaying, } as ReducerState, backupFinished: { ...base, + reducer_type: "backup", backup_state: BackupStates.BackupFinished, } as ReducerState, authEditing: { @@ -272,10 +284,12 @@ export const reducerStatesExample = { } as ReducerState, backupAttributeEditing: { ...base, + reducer_type: "backup", backup_state: BackupStates.UserAttributesCollecting, } as ReducerState, truthsPaying: { ...base, + reducer_type: "backup", backup_state: BackupStates.TruthsPaying, } as ReducerState, }; diff --git a/packages/anastasis-webui/watch/reply.sh b/packages/anastasis-webui/watch/reply.sh new file mode 100755 index 000000000..1b42aa4e3 --- /dev/null +++ b/packages/anastasis-webui/watch/reply.sh @@ -0,0 +1,17 @@ +#!/bin/bash +SERVER_KEY=258EAFA5-E914-47DA-95CA-C5AB0DC85B11 + +while read line; do + LINE=$(echo $line | tr -d '\r') + case $LINE in + Sec-WebSocket-Key:*) + CLIENT_KEY="${LINE:19}" + export WS_ACCEPT=$( echo -n $CLIENT_KEY$SERVER_KEY | sha1sum | xxd -r -p | base64 ) + ;; + "") break ;; + esac +done + +cat watch/web_socket_server.reply | sed 's/$'"/`echo \\\r`/" | envsubst '$WS_ACCEPT' + +socat UNIX-RECV:./send_signal STDOUT diff --git a/packages/anastasis-webui/watch/send_reload.sh b/packages/anastasis-webui/watch/send_reload.sh new file mode 100755 index 000000000..87eef7d54 --- /dev/null +++ b/packages/anastasis-webui/watch/send_reload.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +COMMAND='{"type":"RELOAD"}' +LEN=$(printf '%x\n' ${#COMMAND}) +OPCODE=81 +cat <(echo -n $OPCODE$LEN | xxd -r -p) <(echo -n $COMMAND) | socat - UNIX-SEND:./send_signal + diff --git a/packages/anastasis-webui/watch/serve.sh b/packages/anastasis-webui/watch/serve.sh new file mode 100755 index 000000000..cf2737416 --- /dev/null +++ b/packages/anastasis-webui/watch/serve.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +socat TCP-LISTEN:8003,fork EXEC:"./watch/reply.sh" + diff --git a/packages/anastasis-webui/watch/web_socket_client.request b/packages/anastasis-webui/watch/web_socket_client.request new file mode 100644 index 000000000..e7077b0cb --- /dev/null +++ b/packages/anastasis-webui/watch/web_socket_client.request @@ -0,0 +1,6 @@ +GET /socket HTTP/1.1 +Connection: Upgrade +Upgrade: websocket +Sec-WebSocket-Version: 13 +Sec-WebSocket-Key: aaaaaaaaaaaaaaaaaaaaaa== + diff --git a/packages/anastasis-webui/watch/web_socket_server.reply b/packages/anastasis-webui/watch/web_socket_server.reply new file mode 100644 index 000000000..b4e0db001 --- /dev/null +++ b/packages/anastasis-webui/watch/web_socket_server.reply @@ -0,0 +1,5 @@ +HTTP/1.1 101 Switching Protocols +Upgrade: websocket +Connection: Upgrade +Sec-WebSocket-Accept: $WS_ACCEPT + diff --git a/packages/taler-wallet-webextension/clean_and_build.sh b/packages/taler-wallet-webextension/clean_and_build.sh index 2662f8b2d..fb53124ef 100755 --- a/packages/taler-wallet-webextension/clean_and_build.sh +++ b/packages/taler-wallet-webextension/clean_and_build.sh @@ -2,7 +2,7 @@ set -e -#rm -rf dist lib tsconfig.tsbuildinfo .linaria-cache +rm -rf dist lib tsconfig.tsbuildinfo .linaria-cache echo typecheck and bundle... node build-fast-with-linaria.mjs & diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json index 88baeb261..d9940776c 100644 --- a/packages/taler-wallet-webextension/package.json +++ b/packages/taler-wallet-webextension/package.json @@ -44,6 +44,7 @@ }, "devDependencies": { "@babel/core": "7.13.16", + "@babel/plugin-transform-modules-commonjs": "^7.18.2", "@babel/plugin-transform-react-jsx-source": "^7.12.13", "@babel/preset-typescript": "^7.13.0", "@babel/runtime": "^7.17.8", |