show/hide key
This commit is contained in:
parent
a1af7945d1
commit
3267f56dc3
@ -23,7 +23,7 @@ import { InputProps, useField } from "./useField.js";
|
|||||||
|
|
||||||
export interface Props<T> extends InputProps<T> {
|
export interface Props<T> extends InputProps<T> {
|
||||||
expand?: boolean;
|
expand?: boolean;
|
||||||
inputType?: "text" | "number";
|
inputType?: "text" | "number" | "password";
|
||||||
addonBefore?: ComponentChildren;
|
addonBefore?: ComponentChildren;
|
||||||
addonAfter?: ComponentChildren;
|
addonAfter?: ComponentChildren;
|
||||||
toStr?: (v?: any) => string;
|
toStr?: (v?: any) => string;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser";
|
import { useTranslationContext } from "@gnu-taler/web-util/lib/index.browser";
|
||||||
import { ComponentChildren, h, VNode } from "preact";
|
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useInstanceContext } from "../../context/instance.js";
|
import { useInstanceContext } from "../../context/instance.js";
|
||||||
import { DEFAULT_REQUEST_TIMEOUT } from "../../utils/constants.js";
|
import { DEFAULT_REQUEST_TIMEOUT } from "../../utils/constants.js";
|
||||||
@ -65,16 +65,25 @@ export function ConfirmModal({
|
|||||||
<section class="modal-card-body">{children}</section>
|
<section class="modal-card-body">{children}</section>
|
||||||
<footer class="modal-card-foot">
|
<footer class="modal-card-foot">
|
||||||
<div class="buttons is-right" style={{ width: "100%" }}>
|
<div class="buttons is-right" style={{ width: "100%" }}>
|
||||||
<button class="button " onClick={onCancel}>
|
{onConfirm ? (
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
<Fragment>
|
||||||
</button>
|
<button class="button " onClick={onCancel}>
|
||||||
<button
|
<i18n.Translate>Cancel</i18n.Translate>
|
||||||
class={danger ? "button is-danger " : "button is-info "}
|
</button>
|
||||||
disabled={disabled}
|
|
||||||
onClick={onConfirm}
|
<button
|
||||||
>
|
class={danger ? "button is-danger " : "button is-info "}
|
||||||
<i18n.Translate>{label}</i18n.Translate>
|
disabled={disabled}
|
||||||
</button>
|
onClick={onConfirm}
|
||||||
|
>
|
||||||
|
<i18n.Translate>{label}</i18n.Translate>
|
||||||
|
</button>
|
||||||
|
</Fragment>
|
||||||
|
) : (
|
||||||
|
<button class="button " onClick={onCancel}>
|
||||||
|
<i18n.Translate>Close</i18n.Translate>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
@ -96,20 +96,30 @@ export function QrPage({ template, id: templateId, onBack }: Props): VNode {
|
|||||||
: template.pos_algorithm === 2
|
: template.pos_algorithm === 2
|
||||||
? `otpauth://totp/${issuer}:${templateId}?secret=${template.pos_key}&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
|
? `otpauth://totp/${issuer}:${templateId}?secret=${template.pos_key}&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
|
const keySlice = template.pos_key?.substring(0, 4);
|
||||||
|
|
||||||
|
const oauthUriWithoutSecret = !template.pos_algorithm
|
||||||
|
? undefined
|
||||||
|
: template.pos_algorithm === 1
|
||||||
|
? `otpauth://totp/${issuer}:${templateId}?secret=${keySlice}...&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
|
||||||
|
: template.pos_algorithm === 2
|
||||||
|
? `otpauth://totp/${issuer}:${templateId}?secret=${keySlice}...&issuer=${issuer}&algorithm=SHA1&digits=8&period=30`
|
||||||
|
: undefined;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{oauthUri && (
|
{oauthUri && (
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
description="Setup TOTP"
|
description="Setup TOTP"
|
||||||
active={setupTOTP}
|
active={setupTOTP}
|
||||||
onConfirm={() => {
|
onCancel={() => {
|
||||||
setSetupTOTP(false);
|
setSetupTOTP(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p>Scan this qr code with your TOTP device</p>
|
<p>Scan this qr code with your TOTP device</p>
|
||||||
<QR text={oauthUri} />
|
<QR text={oauthUri} />
|
||||||
<pre style={{ textAlign: "center" }}>
|
<pre style={{ textAlign: "center" }}>
|
||||||
<a href={oauthUri}>{oauthUri}</a>
|
<a href={oauthUri}>{oauthUriWithoutSecret}</a>
|
||||||
</pre>
|
</pre>
|
||||||
</ConfirmModal>
|
</ConfirmModal>
|
||||||
)}
|
)}
|
||||||
|
@ -57,6 +57,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
|
|||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const backend = useBackendContext();
|
const backend = useBackendContext();
|
||||||
|
|
||||||
|
const [showKey, setShowKey] = useState(false);
|
||||||
const [state, setState] = useState<Partial<Entity>>(template);
|
const [state, setState] = useState<Partial<Entity>>(template);
|
||||||
|
|
||||||
const errors: FormErrors<Entity> = {
|
const errors: FormErrors<Entity> = {
|
||||||
@ -161,14 +162,26 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
|
|||||||
convert={(v) => Number(v)}
|
convert={(v) => Number(v)}
|
||||||
/>
|
/>
|
||||||
{state.pos_algorithm && state.pos_algorithm > 0 ? (
|
{state.pos_algorithm && state.pos_algorithm > 0 ? (
|
||||||
<Input<Entity>
|
<InputWithAddon<Entity>
|
||||||
name="pos_key"
|
name="pos_key"
|
||||||
label={i18n.str`Point-of-sale key`}
|
label={i18n.str`Point-of-sale key`}
|
||||||
|
inputType={showKey ? "text" : "password"}
|
||||||
help=""
|
help=""
|
||||||
|
expand
|
||||||
tooltip={i18n.str`Useful to validate the purchase`}
|
tooltip={i18n.str`Useful to validate the purchase`}
|
||||||
|
addonAfter={
|
||||||
|
<span class="icon">
|
||||||
|
{showKey ? (
|
||||||
|
<i class="mdi mdi-eye" />
|
||||||
|
) : (
|
||||||
|
<i class="mdi mdi-eye-off" />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
side={
|
side={
|
||||||
<span data-tooltip={i18n.str`generate random secret key`}>
|
<span>
|
||||||
<button
|
<button
|
||||||
|
data-tooltip={i18n.str`generate random secret key`}
|
||||||
class="button is-info mr-3"
|
class="button is-info mr-3"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
const pos_key = randomBase32Key();
|
const pos_key = randomBase32Key();
|
||||||
@ -177,6 +190,23 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
|
|||||||
>
|
>
|
||||||
<i18n.Translate>random</i18n.Translate>
|
<i18n.Translate>random</i18n.Translate>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
data-tooltip={
|
||||||
|
showKey
|
||||||
|
? i18n.str`show secret key`
|
||||||
|
: i18n.str`hide secret key`
|
||||||
|
}
|
||||||
|
class="button is-info mr-3"
|
||||||
|
onClick={(e) => {
|
||||||
|
setShowKey(!showKey);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{showKey ? (
|
||||||
|
<i18n.Translate>hide</i18n.Translate>
|
||||||
|
) : (
|
||||||
|
<i18n.Translate>show</i18n.Translate>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
Loading…
Reference in New Issue
Block a user