accesstoken in memory and better login when switching between accounts

This commit is contained in:
Sebastian 2023-08-04 13:32:08 -03:00
parent 44aeaba7b4
commit 37d0f9438e
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
4 changed files with 111 additions and 19 deletions

View File

@ -20,7 +20,7 @@
*/
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
import { ComponentChildren, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useBackendContext } from "../../context/backend.js";
import { useInstanceContext } from "../../context/instance.js";
@ -40,7 +40,7 @@ function getTokenValuePart(t: string): string {
}
function normalizeToken(r: string): string {
return `secret-token:${encodeURIComponent(r)}`;
return `secret-token:${r}`;
}
function cleanUp(s: string): string {
@ -53,7 +53,7 @@ function cleanUp(s: string): string {
export function LoginModal({ onConfirm, withMessage }: Props): VNode {
const { url: backendUrl, token: baseToken } = useBackendContext();
const { admin, token: instanceToken } = useInstanceContext();
const { admin, token: instanceToken, id } = useInstanceContext();
const testLogin = useCredentialsChecker();
const currentToken = getTokenValuePart(
(!admin ? baseToken : instanceToken) ?? "",
@ -63,6 +63,78 @@ export function LoginModal({ onConfirm, withMessage }: Props): VNode {
const [url, setURL] = useState(cleanUp(backendUrl));
const { i18n } = useTranslationContext();
if (admin && id !== "default") {
//admin trying to access another instance
return (<div class="columns is-centered" style={{ margin: "auto" }}>
<div class="column is-two-thirds ">
<div class="modal-card" style={{ width: "100%", margin: 0 }}>
<header
class="modal-card-head"
style={{ border: "1px solid", borderBottom: 0 }}
>
<p class="modal-card-title">{i18n.str`Login required`}</p>
</header>
<section
class="modal-card-body"
style={{ border: "1px solid", borderTop: 0, borderBottom: 0 }}
>
<p>
<i18n.Translate>Need the access token for the instance.</i18n.Translate>
</p>
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">
<i18n.Translate>Access Token</i18n.Translate>
</label>
</div>
<div class="field-body">
<div class="field">
<p class="control is-expanded">
<input
class="input"
type="password"
placeholder={"set new access token"}
name="token"
onKeyPress={(e) =>
e.keyCode === 13
? onConfirm(url, normalizeToken(token))
: null
}
value={token}
onInput={(e): void => setToken(e?.currentTarget.value)}
/>
</p>
</div>
</div>
</div>
</section>
<footer
class="modal-card-foot "
style={{
justifyContent: "flex-end",
border: "1px solid",
borderTop: 0,
}}
>
<AsyncButton
onClick={async () => {
const secretToken = normalizeToken(token);
const { valid, cause } = await testLogin(`${url}/instances/${id}`, secretToken);
if (valid) {
onConfirm(url, secretToken);
} else {
onConfirm(url);
}
}}
>
<i18n.Translate>Confirm</i18n.Translate>
</AsyncButton>
</footer>
</div>
</div>
</div>)
}
return (
<div class="columns is-centered" style={{ margin: "auto" }}>
<div class="column is-two-thirds ">
@ -137,8 +209,7 @@ export function LoginModal({ onConfirm, withMessage }: Props): VNode {
borderTop: 0,
}}
>
<button
class="button is-info"
<AsyncButton
onClick={async () => {
const secretToken = normalizeToken(token);
const { valid, cause } = await testLogin(url, secretToken);
@ -150,10 +221,24 @@ export function LoginModal({ onConfirm, withMessage }: Props): VNode {
}}
>
<i18n.Translate>Confirm</i18n.Translate>
</button>
</AsyncButton>
</footer>
</div>
</div>
</div>
);
}
function AsyncButton({onClick, children}:{onClick: () => Promise<void>, children: ComponentChildren}):VNode {
const [running, setRunning] = useState(false)
return <button class="button is-info" disabled={running} onClick={() => {
setRunning(true)
onClick().then(() => {
setRunning(false)
}).catch(() => {
setRunning(false)
})
}}>
{children}
</button>
}

View File

@ -130,7 +130,12 @@ export function Menu({
)}
{mimic && (
<nav class="level">
<nav class="level" style={{
zIndex: 100,
position:"fixed",
width:"50%",
marginLeft: "20%"
}}>
<div class="level-item has-text-centered has-background-warning">
<p class="is-size-5">
You are viewing the instance <b>&quot;{instance}&quot;</b>.{" "}

View File

@ -21,6 +21,7 @@
import { StateUpdater, useCallback, useState } from "preact/hooks";
import { ValueOrFunction } from "../utils/types.js";
import { useMemoryStorage } from "@gnu-taler/web-util/browser";
const calculateRootPath = () => {
const rootPath =
@ -52,14 +53,15 @@ export function useBackendURL(
export function useBackendDefaultToken(
initialValue?: string,
): [string | undefined, StateUpdater<string | undefined>] {
return useLocalStorage("backend-token", initialValue);
): [string | undefined, ((d:string | undefined) => void)] {
const {update, value} = useMemoryStorage(`backend-token`, initialValue)
return [value, update];
}
export function useBackendInstanceToken(
id: string,
): [string | undefined, StateUpdater<string | undefined>] {
const [token, setToken] = useLocalStorage(`backend-token-${id}`);
): [string | undefined, ((d:string | undefined) => void)] {
const {update:setToken, value:token, reset} = useMemoryStorage(`backend-token-${id}`)
const [defaultToken, defaultSetToken] = useBackendDefaultToken();
// instance named 'default' use the default token
@ -67,15 +69,16 @@ export function useBackendInstanceToken(
return [defaultToken, defaultSetToken];
}
function updateToken(
value:
| (string | undefined)
| ((s: string | undefined) => string | undefined),
value: (string | undefined)
): void {
setToken((p) => {
const toStore = value instanceof Function ? value(p) : value;
return toStore;
});
console.log("seeting token", value)
if (value === undefined) {
reset()
} else {
setToken(value)
}
}
console.log("token", token)
return [token, updateToken];
}

View File

@ -25,7 +25,6 @@ import { Link } from "preact-router";
export default function NotFoundPage(): VNode {
return (
<div>
<h1>Error 404</h1>
<p>That page doesn&apos;t exist.</p>
<Link href="/">
<h4>Back to Home</h4>