show qr to import TOTP into other app

This commit is contained in:
Sebastian 2023-06-23 10:36:24 -03:00
parent 9dbf0bd7d2
commit 4f30506dca
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
2 changed files with 143 additions and 93 deletions

View File

@ -24,7 +24,7 @@ import {
MerchantTemplateContractDetails,
} from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
import {
@ -44,6 +44,8 @@ import {
randomBase32Key,
} from "../../../../utils/crypto.js";
import { undefinedIfEmpty } from "../../../../utils/table.js";
import { QR } from "../../../../components/exception/QR.js";
import { useInstanceContext } from "../../../../context/instance.js";
type Entity = MerchantBackend.Template.TemplateAddDetails;
@ -58,6 +60,8 @@ const algorithmsNames = ["off", "30s 8d TOTP-SHA1", "30s 8d eTOTP-SHA1"];
export function CreatePage({ onCreate, onBack }: Props): VNode {
const { i18n } = useTranslationContext();
const backend = useBackendContext();
const { id: instanceId } = useInstanceContext();
const issuer = new URL(backend.url).hostname;
const [showKey, setShowKey] = useState(false);
const [state, setState] = useState<Partial<Entity>>({
@ -120,6 +124,8 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
return onCreate(state as any);
};
const qrText = `otpauth://totp/${instanceId}/${state.template_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${state.pos_key}`;
return (
<div>
<section class="section is-main-section">
@ -175,6 +181,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
fromStr={(v) => Number(v)}
/>
{state.pos_algorithm && state.pos_algorithm > 0 ? (
<Fragment>
<InputWithAddon<Entity>
name="pos_key"
label={i18n.str`Point-of-sale key`}
@ -223,6 +230,24 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
</span>
}
/>
{showKey && (
<Fragment>
<QR text={qrText} />
<div
style={{
color: "grey",
fontSize: "small",
width: 200,
textAlign: "center",
margin: "auto",
wordBreak: "break-all",
}}
>
{qrText}
</div>
</Fragment>
)}
</Fragment>
) : undefined}
</FormProvider>

View File

@ -24,7 +24,7 @@ import {
MerchantTemplateContractDetails,
} from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
import {
@ -44,6 +44,8 @@ import {
randomBase32Key,
} from "../../../../utils/crypto.js";
import { undefinedIfEmpty } from "../../../../utils/table.js";
import { QR } from "../../../../components/exception/QR.js";
import { useInstanceContext } from "../../../../context/instance.js";
type Entity = MerchantBackend.Template.TemplatePatchDetails & WithId;
@ -59,6 +61,8 @@ const algorithmsNames = ["off", "30s 8d TOTP-SHA1", "30s 8d eTOTP-SHA1"];
export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
const { i18n } = useTranslationContext();
const backend = useBackendContext();
const { id: instanceId } = useInstanceContext();
const issuer = new URL(backend.url).hostname;
const [showKey, setShowKey] = useState(false);
const [state, setState] = useState<Partial<Entity>>(template);
@ -113,6 +117,8 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
return onUpdate(state as any);
};
const qrText = `otpauth://totp/${instanceId}/${state.id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${state.pos_key}`;
return (
<div>
<section class="section">
@ -185,6 +191,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
fromStr={(v) => Number(v)}
/>
{state.pos_algorithm && state.pos_algorithm > 0 ? (
<Fragment>
<InputWithAddon<Entity>
name="pos_key"
label={i18n.str`Point-of-sale key`}
@ -234,6 +241,24 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
</span>
}
/>
{showKey && (
<Fragment>
<QR text={qrText} />
<div
style={{
color: "grey",
fontSize: "small",
width: 200,
textAlign: "center",
margin: "auto",
wordBreak: "break-all",
}}
>
{qrText}
</div>
</Fragment>
)}
</Fragment>
) : undefined}
</FormProvider>