summaryrefslogtreecommitdiff
path: root/packages/anastasis-webui
diff options
context:
space:
mode:
Diffstat (limited to 'packages/anastasis-webui')
-rw-r--r--packages/anastasis-webui/package.json2
-rw-r--r--packages/anastasis-webui/src/components/menu/SideBar.tsx5
-rw-r--r--packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts6
-rw-r--r--packages/anastasis-webui/src/index.html2
-rw-r--r--packages/anastasis-webui/src/index.ts2
-rw-r--r--packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts89
-rw-r--r--packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts24
-rw-r--r--packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx4
-rw-r--r--packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx7
-rw-r--r--packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx13
10 files changed, 99 insertions, 55 deletions
diff --git a/packages/anastasis-webui/package.json b/packages/anastasis-webui/package.json
index c1c2925a2..108b1476e 100644
--- a/packages/anastasis-webui/package.json
+++ b/packages/anastasis-webui/package.json
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@gnu-taler/anastasis-webui",
- "version": "0.2.99",
+ "version": "0.10.7",
"license": "MIT",
"type": "module",
"scripts": {
diff --git a/packages/anastasis-webui/src/components/menu/SideBar.tsx b/packages/anastasis-webui/src/components/menu/SideBar.tsx
index 3dac73e04..31bc3c7a7 100644
--- a/packages/anastasis-webui/src/components/menu/SideBar.tsx
+++ b/packages/anastasis-webui/src/components/menu/SideBar.tsx
@@ -29,7 +29,10 @@ interface Props {
}
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : "dev";
-const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
+const GIT_HASH =
+ typeof __GIT_HASH__ !== "undefined"
+ ? __GIT_HASH__.substring(0, 7)
+ : undefined;
const VERSION_WITH_HASH = GIT_HASH ? `${VERSION}-${GIT_HASH}` : VERSION;
export function Sidebar({ mobile }: Props): VNode {
diff --git a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
index fc8c4cf6c..fcc380775 100644
--- a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
+++ b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts
@@ -303,7 +303,7 @@ export function useAnastasisReducer(): AnastasisReducerApi {
},
});
} catch (e) {
- throw Error("could not restore the state");
+ throw new Error("could not restore the state");
}
},
async discoverStart(): Promise<void> {
@@ -399,7 +399,7 @@ export function useAnastasisReducer(): AnastasisReducerApi {
}
class ReducerTxImpl implements ReducerTransactionHandle {
- constructor(public transactionState: ReducerState) { }
+ constructor(public transactionState: ReducerState) {}
async transition(action: string, args: any): Promise<ReducerState> {
let s: ReducerState;
if (remoteReducer) {
@@ -410,7 +410,7 @@ class ReducerTxImpl implements ReducerTransactionHandle {
this.transactionState = s;
// Abort transaction as soon as we transition into an error state.
if (this.transactionState.reducer_type === "error") {
- throw Error("transition resulted in error");
+ throw new Error("transition resulted in error");
}
return this.transactionState;
}
diff --git a/packages/anastasis-webui/src/index.html b/packages/anastasis-webui/src/index.html
index 90a795ae3..d64b627e4 100644
--- a/packages/anastasis-webui/src/index.html
+++ b/packages/anastasis-webui/src/index.html
@@ -32,7 +32,7 @@
/>
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
<title>Anastasis</title>
- <!-- Entry point for the demobank SPA. -->
+ <!-- Entry point for the SPA. -->
<script type="module" src="index.js"></script>
<link rel="stylesheet" href="index.css" />
</head>
diff --git a/packages/anastasis-webui/src/index.ts b/packages/anastasis-webui/src/index.ts
index d7b2164ab..f614e4f54 100644
--- a/packages/anastasis-webui/src/index.ts
+++ b/packages/anastasis-webui/src/index.ts
@@ -22,7 +22,7 @@ function main(): void {
try {
const container = document.getElementById("container");
if (!container) {
- throw Error("container not found, can't mount page contents");
+ throw new Error("container not found, can't mount page contents");
}
render(h(App, {}), container);
} catch (e) {
diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts
index 0ab275f54..ed8301d65 100644
--- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts
+++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/index.ts
@@ -24,7 +24,7 @@ import { WithoutProviderType, WithProviderType } from "./views.js";
export type AuthProvByStatusMap = Record<
AuthenticationProviderStatus["status"],
(AuthenticationProviderStatus & { url: string })[]
->
+>;
export type State = NoReducer | InvalidState | WithType | WithoutType;
@@ -63,42 +63,69 @@ const map: StateViewMap<State> = {
"without-type": WithoutProviderType,
};
-export default compose("AddingProviderScreen", useComponentState, map)
-
+export default compose("AddingProviderScreen", useComponentState, map);
+const providerResponseCache = new Map<string, any>(); // `any` is the return type of res.json()
export async function testProvider(
url: string,
expectedMethodType?: string,
): Promise<void> {
+ const testFatalPrefix = `Encountered a fatal error whilst testing the provider ${url}`;
+ let configUrl = "";
try {
- const response = await fetch(new URL("config", url).href);
- const json = await response.json().catch((d) => ({}));
- if (!("methods" in json) || !Array.isArray(json.methods)) {
- throw Error(
- "This provider doesn't have authentication method. Check the provider URL",
- );
- }
- if (!expectedMethodType) {
- return;
- }
- let found = false;
- for (let i = 0; i < json.methods.length && !found; i++) {
- found = json.methods[i].type === expectedMethodType;
- }
- if (!found) {
- throw Error(
- `This provider does not support authentication method ${expectedMethodType}`,
- );
- }
+ configUrl = new URL("config", url).href;
+ } catch (error) {
+ throw new Error(`${testFatalPrefix}: Invalid Provider URL: ${url}
+Error: ${error}`);
+ }
+ // TODO: look into using core.getProviderInfo :)
+ const providerHasUrl = providerResponseCache.has(url);
+ const json = providerHasUrl
+ ? providerResponseCache.get(url)
+ : await fetch(configUrl)
+ .catch((error) => {
+ throw new Error(`${testFatalPrefix}: Could not connect: ${error}
+Please check the URL.`);
+ })
+ .then(async (response) => {
+ if (!response.ok)
+ throw new Error(
+ `${testFatalPrefix}: The server ${response.url} responded with a non-2xx response.`,
+ );
+ try {
+ return await response.json();
+ } catch (error) {
+ throw new Error(
+ `${testFatalPrefix}: The server responded with malformed JSON.\nError: ${error}`,
+ );
+ }
+ });
+ if (typeof json !== "object")
+ throw new Error(
+ `${testFatalPrefix}: Did not get an object after decoding.`,
+ );
+ if (!("name" in json) || json.name !== "anastasis") {
+ throw new Error(
+ `${testFatalPrefix}: The provider does not appear to be an Anastasis provider. Please check the provider's URL.`,
+ );
+ }
+ if (!("methods" in json) || !Array.isArray(json.methods)) {
+ throw new Error(
+ "This provider doesn't have authentication method. Please check the provider's URL and ensure it is properly configured.",
+ );
+ }
+ if (!providerHasUrl) providerResponseCache.set(url, json);
+ if (!expectedMethodType) {
return;
- } catch (e) {
- console.log("ERROR testProvider", e);
- const error =
- e instanceof Error
- ? Error(
- `There was an error testing this provider, try another one. ${e.message}`,
- )
- : Error(`There was an error testing this provider, try another one.`);
- throw error;
}
+ let found = false;
+ for (let i = 0; i < json.methods.length && !found; i++) {
+ found = json.methods[i].type === expectedMethodType;
+ }
+ if (!found) {
+ throw new Error(
+ `${testFatalPrefix}: This provider does not support authentication method ${expectedMethodType}`,
+ );
+ }
+ return;
}
diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts
index f80f1c464..30e4d750d 100644
--- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts
+++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/state.ts
@@ -76,14 +76,23 @@ export default function useComponentState({
useEffect(() => {
if (timeout.current) clearTimeout(timeout.current);
timeout.current = setTimeout(async () => {
- const url = providerURL.endsWith("/") ? providerURL : providerURL + "/";
- if (!providerURL || authProviders.includes(url)) return;
+ let url = providerURL;
+ if (!url || authProviders.includes(url)) return;
+ if (url && !url.match(/^(https?:)\/\/.+\/(?:config)?$/iu))
+ return setError(
+ "Malformed URL: Must be an HTTP(S) URL ending with a /",
+ );
+ if (url.endsWith("/config")) url = url.substring(0, url.length - 6);
try {
setTesting(true);
await testProvider(url, providerType);
setError("");
} catch (e) {
if (e instanceof Error) setError(e.message);
+ else
+ throw new Error(
+ `Unexpected Error Type: ${typeof e} - Cannot handle. Error: ${e}`,
+ );
}
setTesting(false);
}, 200);
@@ -114,11 +123,12 @@ export default function useComponentState({
let errors = !providerURL ? "Add provider URL" : undefined;
let url: string | undefined;
- try {
- url = new URL("", providerURL).href;
- } catch {
- errors = "Check the URL";
- }
+ // We'll validate it in testProvider & via a regex above - there's no need in this :)
+ // try {
+ // url = new URL("", providerURL).href;
+ // } catch {
+ // errors = "Check the URL";
+ // }
const _url = url;
if (!!error && !errors) {
diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx
index 19557a12f..00a42a949 100644
--- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx
+++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen/views.tsx
@@ -121,13 +121,13 @@ export function WithoutProviderType(props: WithoutType): VNode {
<div class="container">
<TextInput
label="Provider URL"
- placeholder="https://provider.com"
+ placeholder="https://provider.com/"
grabFocus
error={props.errors}
bind={[props.providerURL, props.setProviderURL]}
/>
</div>
- <p class="block">Example: https://kudos.demo.anastasis.lu</p>
+ <p class="block">Example: https://kudos.demo.anastasis.lu/</p>
{props.testing && <p class="has-text-info">Testing</p>}
<div
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
index 228186a2d..1f8cea7aa 100644
--- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx
@@ -97,13 +97,11 @@ export function AttributeEntryScreen(): VNode {
function saveAsPDF(): void {
const printWindow = window.open("", "", "height=400,width=800");
const divContents = document.getElementById("printThis");
- const styleContents = document.getElementById("style-id");
- if (!printWindow || !divContents || !styleContents) return;
+ if (!printWindow || !divContents) return;
printWindow.document.write(
- "<html><head><title>Anastasis Recovery Document</title><style>",
+ `<html><head><link rel="stylesheet" href="index.css" /><title>Anastasis Recovery Document</title><style>`,
);
- printWindow.document.write(styleContents.innerHTML);
printWindow.document.write("</style></head><body>&nbsp;</body></html>");
printWindow.document.close();
printWindow.document.body.appendChild(divContents.cloneNode(true));
@@ -132,6 +130,7 @@ export function AttributeEntryScreen(): VNode {
secret will be safely stored. If you forget what you have entered or
if there is a misspell you will be unable to recover your secret.
<p>
+ {/* TODO: make this actually work reliably cross-browser lol (opens about:blank for me) */}
<a onClick={saveAsPDF}>Save the personal information as PDF</a>
</p>
</ConfirmModal>
diff --git a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
index 62ac410a2..f528bc207 100644
--- a/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/RecoveryFinishedScreen.tsx
@@ -58,9 +58,14 @@ export function RecoveryFinishedScreen(): VNode {
const secret = bytesToString(decodeCrock(encodedSecret.value));
const plainText =
encodedSecret.value.length < 1000 && encodedSecret.mime === "text/plain";
- const contentURI = !plainText
- ? secret
- : `data:${encodedSecret.mime},${secret}`;
+
+ let [uri, setUri] = useState(`data:${encodedSecret.mime},${secret}`);
+ fetch(`data:${encodedSecret.mime},${secret}`) // TODO: look into using new Blob
+ .then((v) => v.blob())
+ .then((blob) => URL.createObjectURL(blob))
+ .then((newUri) => {
+ setUri(newUri);
+ });
return (
<AnastasisClientFrame title="Recovery Success" hideNav>
<h2 class="subtitle">Your secret was recovered</h2>
@@ -87,7 +92,7 @@ export function RecoveryFinishedScreen(): VNode {
download={
encodedSecret.filename ? encodedSecret.filename : "secret.file"
}
- href={contentURI}
+ href={uri}
>
<div class="icon is-small ">
<i class="mdi mdi-download" />