show qr to import TOTP into other app
This commit is contained in:
parent
9dbf0bd7d2
commit
4f30506dca
@ -24,7 +24,7 @@ import {
|
|||||||
MerchantTemplateContractDetails,
|
MerchantTemplateContractDetails,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
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 { useState } from "preact/hooks";
|
||||||
import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
|
import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
|
||||||
import {
|
import {
|
||||||
@ -44,6 +44,8 @@ import {
|
|||||||
randomBase32Key,
|
randomBase32Key,
|
||||||
} from "../../../../utils/crypto.js";
|
} from "../../../../utils/crypto.js";
|
||||||
import { undefinedIfEmpty } from "../../../../utils/table.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;
|
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 {
|
export function CreatePage({ onCreate, onBack }: Props): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const backend = useBackendContext();
|
const backend = useBackendContext();
|
||||||
|
const { id: instanceId } = useInstanceContext();
|
||||||
|
const issuer = new URL(backend.url).hostname;
|
||||||
|
|
||||||
const [showKey, setShowKey] = useState(false);
|
const [showKey, setShowKey] = useState(false);
|
||||||
const [state, setState] = useState<Partial<Entity>>({
|
const [state, setState] = useState<Partial<Entity>>({
|
||||||
@ -120,6 +124,8 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
|
|||||||
return onCreate(state as any);
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<section class="section is-main-section">
|
<section class="section is-main-section">
|
||||||
@ -175,6 +181,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
|
|||||||
fromStr={(v) => Number(v)}
|
fromStr={(v) => Number(v)}
|
||||||
/>
|
/>
|
||||||
{state.pos_algorithm && state.pos_algorithm > 0 ? (
|
{state.pos_algorithm && state.pos_algorithm > 0 ? (
|
||||||
|
<Fragment>
|
||||||
<InputWithAddon<Entity>
|
<InputWithAddon<Entity>
|
||||||
name="pos_key"
|
name="pos_key"
|
||||||
label={i18n.str`Point-of-sale key`}
|
label={i18n.str`Point-of-sale key`}
|
||||||
@ -223,6 +230,24 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
|
|||||||
</span>
|
</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}
|
) : undefined}
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ import {
|
|||||||
MerchantTemplateContractDetails,
|
MerchantTemplateContractDetails,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { useTranslationContext } from "@gnu-taler/web-util/browser";
|
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 { useState } from "preact/hooks";
|
||||||
import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
|
import { AsyncButton } from "../../../../components/exception/AsyncButton.js";
|
||||||
import {
|
import {
|
||||||
@ -44,6 +44,8 @@ import {
|
|||||||
randomBase32Key,
|
randomBase32Key,
|
||||||
} from "../../../../utils/crypto.js";
|
} from "../../../../utils/crypto.js";
|
||||||
import { undefinedIfEmpty } from "../../../../utils/table.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;
|
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 {
|
export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const backend = useBackendContext();
|
const backend = useBackendContext();
|
||||||
|
const { id: instanceId } = useInstanceContext();
|
||||||
|
const issuer = new URL(backend.url).hostname;
|
||||||
|
|
||||||
const [showKey, setShowKey] = useState(false);
|
const [showKey, setShowKey] = useState(false);
|
||||||
const [state, setState] = useState<Partial<Entity>>(template);
|
const [state, setState] = useState<Partial<Entity>>(template);
|
||||||
@ -113,6 +117,8 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
|
|||||||
return onUpdate(state as any);
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<section class="section">
|
<section class="section">
|
||||||
@ -185,6 +191,7 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
|
|||||||
fromStr={(v) => Number(v)}
|
fromStr={(v) => Number(v)}
|
||||||
/>
|
/>
|
||||||
{state.pos_algorithm && state.pos_algorithm > 0 ? (
|
{state.pos_algorithm && state.pos_algorithm > 0 ? (
|
||||||
|
<Fragment>
|
||||||
<InputWithAddon<Entity>
|
<InputWithAddon<Entity>
|
||||||
name="pos_key"
|
name="pos_key"
|
||||||
label={i18n.str`Point-of-sale key`}
|
label={i18n.str`Point-of-sale key`}
|
||||||
@ -234,6 +241,24 @@ export function UpdatePage({ template, onUpdate, onBack }: Props): VNode {
|
|||||||
</span>
|
</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}
|
) : undefined}
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user