gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: show qr to import TOTP into o


From: gnunet
Subject: [taler-wallet-core] branch master updated: show qr to import TOTP into other app
Date: Fri, 23 Jun 2023 15:36:30 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 4f30506dc show qr to import TOTP into other app
4f30506dc is described below

commit 4f30506dcacc587586381b1a8fa20c5442784e41
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Jun 23 10:36:24 2023 -0300

    show qr to import TOTP into other app
---
 .../paths/instance/templates/create/CreatePage.tsx | 117 ++++++++++++--------
 .../paths/instance/templates/update/UpdatePage.tsx | 119 +++++++++++++--------
 2 files changed, 143 insertions(+), 93 deletions(-)

diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
index 137d50b3e..4dde202c4 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
@@ -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,54 +181,73 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
                 fromStr={(v) => Number(v)}
               />
               {state.pos_algorithm && state.pos_algorithm > 0 ? (
-                <InputWithAddon<Entity>
-                  name="pos_key"
-                  label={i18n.str`Point-of-sale key`}
-                  inputType={showKey ? "text" : "password"}
-                  help="Be sure to be very hard to guess or use the random 
generator"
-                  tooltip={i18n.str`Useful to validate the purchase`}
-                  fromStr={(v) => v.toUpperCase()}
-                  addonAfter={
-                    <span class="icon">
-                      {showKey ? (
-                        <i class="mdi mdi-eye" />
-                      ) : (
-                        <i class="mdi mdi-eye-off" />
-                      )}
-                    </span>
-                  }
-                  side={
-                    <span style={{ display: "flex" }}>
-                      <button
-                        data-tooltip={i18n.str`generate random secret key`}
-                        class="button is-info mr-3"
-                        onClick={(e) => {
-                          const pos_key = randomBase32Key();
-                          setState((s) => ({ ...s, pos_key }));
-                        }}
-                      >
-                        <i18n.Translate>random</i18n.Translate>
-                      </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);
-                        }}
-                      >
+                <Fragment>
+                  <InputWithAddon<Entity>
+                    name="pos_key"
+                    label={i18n.str`Point-of-sale key`}
+                    inputType={showKey ? "text" : "password"}
+                    help="Be sure to be very hard to guess or use the random 
generator"
+                    tooltip={i18n.str`Useful to validate the purchase`}
+                    fromStr={(v) => v.toUpperCase()}
+                    addonAfter={
+                      <span class="icon">
                         {showKey ? (
-                          <i18n.Translate>hide</i18n.Translate>
+                          <i class="mdi mdi-eye" />
                         ) : (
-                          <i18n.Translate>show</i18n.Translate>
+                          <i class="mdi mdi-eye-off" />
                         )}
-                      </button>
-                    </span>
-                  }
-                />
+                      </span>
+                    }
+                    side={
+                      <span style={{ display: "flex" }}>
+                        <button
+                          data-tooltip={i18n.str`generate random secret key`}
+                          class="button is-info mr-3"
+                          onClick={(e) => {
+                            const pos_key = randomBase32Key();
+                            setState((s) => ({ ...s, pos_key }));
+                          }}
+                        >
+                          <i18n.Translate>random</i18n.Translate>
+                        </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>
+                    }
+                  />
+                  {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>
 
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
index 20e40cf9b..30e5502bb 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
@@ -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,55 +191,74 @@ export function UpdatePage({ template, onUpdate, onBack 
}: Props): VNode {
                   fromStr={(v) => Number(v)}
                 />
                 {state.pos_algorithm && state.pos_algorithm > 0 ? (
-                  <InputWithAddon<Entity>
-                    name="pos_key"
-                    label={i18n.str`Point-of-sale key`}
-                    inputType={showKey ? "text" : "password"}
-                    help="Be sure to be very hard to guess or use the random 
generator"
-                    expand
-                    tooltip={i18n.str`Useful to validate the purchase`}
-                    fromStr={(v) => v.toUpperCase()}
-                    addonAfter={
-                      <span class="icon">
-                        {showKey ? (
-                          <i class="mdi mdi-eye" />
-                        ) : (
-                          <i class="mdi mdi-eye-off" />
-                        )}
-                      </span>
-                    }
-                    side={
-                      <span style={{ display: "flex" }}>
-                        <button
-                          data-tooltip={i18n.str`generate random secret key`}
-                          class="button is-info mr-3"
-                          onClick={(e) => {
-                            const pos_key = randomBase32Key();
-                            setState((s) => ({ ...s, pos_key }));
-                          }}
-                        >
-                          <i18n.Translate>random</i18n.Translate>
-                        </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);
-                          }}
-                        >
+                  <Fragment>
+                    <InputWithAddon<Entity>
+                      name="pos_key"
+                      label={i18n.str`Point-of-sale key`}
+                      inputType={showKey ? "text" : "password"}
+                      help="Be sure to be very hard to guess or use the random 
generator"
+                      expand
+                      tooltip={i18n.str`Useful to validate the purchase`}
+                      fromStr={(v) => v.toUpperCase()}
+                      addonAfter={
+                        <span class="icon">
                           {showKey ? (
-                            <i18n.Translate>hide</i18n.Translate>
+                            <i class="mdi mdi-eye" />
                           ) : (
-                            <i18n.Translate>show</i18n.Translate>
+                            <i class="mdi mdi-eye-off" />
                           )}
-                        </button>
-                      </span>
-                    }
-                  />
+                        </span>
+                      }
+                      side={
+                        <span style={{ display: "flex" }}>
+                          <button
+                            data-tooltip={i18n.str`generate random secret key`}
+                            class="button is-info mr-3"
+                            onClick={(e) => {
+                              const pos_key = randomBase32Key();
+                              setState((s) => ({ ...s, pos_key }));
+                            }}
+                          >
+                            <i18n.Translate>random</i18n.Translate>
+                          </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>
+                      }
+                    />
+                    {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>
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]