diff options
author | Florian Dold <florian@dold.me> | 2024-01-30 23:09:52 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2024-01-30 23:10:01 +0100 |
commit | f14c643f4a66fc56199eb4aba66a7d5429911db7 (patch) | |
tree | 2410fe2516d51a9fd1b48b38bd10e803cee63b8b | |
parent | c5f97c8f493b52f9e083548d0ac71592c56a2b79 (diff) |
harness,util,others: complete otp integration test, move rfc3548 to taler-utilv0.9.4-dev.10
-rw-r--r-- | packages/auditor-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx | 31 | ||||
-rw-r--r-- | packages/auditor-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx | 47 | ||||
-rw-r--r-- | packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx | 27 | ||||
-rw-r--r-- | packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx | 47 | ||||
-rw-r--r-- | packages/merchant-backoffice-ui/src/utils/crypto.ts | 61 | ||||
-rw-r--r-- | packages/taler-harness/src/integrationtests/test-otp.ts | 10 | ||||
-rw-r--r-- | packages/taler-util/src/index.ts | 75 | ||||
-rw-r--r-- | packages/taler-util/src/rfc3548.ts (renamed from packages/auditor-backoffice-ui/src/utils/crypto.ts) | 23 |
8 files changed, 150 insertions, 171 deletions
diff --git a/packages/auditor-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx b/packages/auditor-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx index 5f1ae26a3..ffeaa064a 100644 --- a/packages/auditor-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx +++ b/packages/auditor-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx @@ -19,6 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { isRfc3548Base32Charset, randomRfc3548Base32Key } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -28,16 +29,10 @@ import { FormProvider, } from "../../../../components/form/FormProvider.js"; import { Input } from "../../../../components/form/Input.js"; -import { InputCurrency } from "../../../../components/form/InputCurrency.js"; -import { InputDuration } from "../../../../components/form/InputDuration.js"; -import { InputNumber } from "../../../../components/form/InputNumber.js"; -import { useBackendContext } from "../../../../context/backend.js"; -import { MerchantBackend } from "../../../../declaration.js"; import { InputSelector } from "../../../../components/form/InputSelector.js"; import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; -import { isBase32RFC3548Charset, randomBase32Key } from "../../../../utils/crypto.js"; -import { QR } from "../../../../components/exception/QR.js"; -import { useInstanceContext } from "../../../../context/instance.js"; +import { useBackendContext } from "../../../../context/backend.js"; +import { MerchantBackend } from "../../../../declaration.js"; type Entity = MerchantBackend.OTP.OtpDeviceAddDetails; @@ -49,7 +44,6 @@ interface Props { const algorithms = [0, 1, 2]; const algorithmsNames = ["off", "30s 8d TOTP-SHA1", "30s 8d eTOTP-SHA1"]; - export function CreatePage({ onCreate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); const backend = useBackendContext(); @@ -59,22 +53,24 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { const [showKey, setShowKey] = useState(false); const errors: FormErrors<Entity> = { - otp_device_id: !state.otp_device_id ? i18n.str`required` + otp_device_id: !state.otp_device_id + ? i18n.str`required` : !/[a-zA-Z0-9]*/.test(state.otp_device_id) ? i18n.str`no valid. only characters and numbers` : undefined, otp_algorithm: !state.otp_algorithm ? i18n.str`required` : undefined, - otp_key: !state.otp_key ? i18n.str`required` : - !isBase32RFC3548Charset(state.otp_key) + otp_key: !state.otp_key + ? i18n.str`required` + : !isRfc3548Base32Charset(state.otp_key) ? i18n.str`just letters and numbers from 2 to 7` : state.otp_key.length !== 32 ? i18n.str`size of the key should be 32` : undefined, - otp_device_description: !state.otp_device_description ? i18n.str`required` + otp_device_description: !state.otp_device_description + ? i18n.str`required` : !/[a-zA-Z0-9]*/.test(state.otp_device_description) ? i18n.str`no valid. only characters and numbers` : undefined, - }; const hasErrors = Object.keys(errors).some( @@ -129,7 +125,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { setShowKey(!showKey); }} addonAfter={ - <span class="icon" > + <span class="icon"> {showKey ? ( <i class="mdi mdi-eye" /> ) : ( @@ -142,7 +138,10 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { data-tooltip={i18n.str`generate random secret key`} class="button is-info mr-3" onClick={(e) => { - setState((s) => ({ ...s, otp_key: randomBase32Key() })); + setState((s) => ({ + ...s, + otp_key: randomRfc3548Base32Key(), + })); }} > <i18n.Translate>random</i18n.Translate> diff --git a/packages/auditor-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx b/packages/auditor-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx index b82807cc7..85bb272aa 100644 --- a/packages/auditor-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx +++ b/packages/auditor-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx @@ -19,6 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { randomRfc3548Base32Key } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -28,10 +29,9 @@ import { FormProvider, } from "../../../../components/form/FormProvider.js"; import { Input } from "../../../../components/form/Input.js"; -import { MerchantBackend, WithId } from "../../../../declaration.js"; import { InputSelector } from "../../../../components/form/InputSelector.js"; import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; -import { randomBase32Key } from "../../../../utils/crypto.js"; +import { MerchantBackend, WithId } from "../../../../declaration.js"; type Entity = MerchantBackend.OTP.OtpDevicePatchDetails & WithId; @@ -48,8 +48,7 @@ export function UpdatePage({ device, onUpdate, onBack }: Props): VNode { const [state, setState] = useState<Partial<Entity>>(device); const [showKey, setShowKey] = useState(false); - const errors: FormErrors<Entity> = { - }; + const errors: FormErrors<Entity> = {}; const hasErrors = Object.keys(errors).some( (k) => (errors as any)[k] !== undefined, @@ -106,16 +105,23 @@ export function UpdatePage({ device, onUpdate, onBack }: Props): VNode { label={i18n.str`Device key`} readonly={state.otp_key === undefined} inputType={showKey ? "text" : "password"} - help={state.otp_key === undefined ? "Not modified" : "Be sure to be very hard to guess or use the random generator"} + help={ + state.otp_key === undefined + ? "Not modified" + : "Be sure to be very hard to guess or use the random generator" + } tooltip={i18n.str`Your device need to have exactly the same value`} fromStr={(v) => v.toUpperCase()} addonAfterAction={() => { setShowKey(!showKey); }} addonAfter={ - <span class="icon" onClick={() => { - setShowKey(!showKey); - }}> + <span + class="icon" + onClick={() => { + setShowKey(!showKey); + }} + > {showKey ? ( <i class="mdi mdi-eye" /> ) : ( @@ -124,25 +130,34 @@ export function UpdatePage({ device, onUpdate, onBack }: Props): VNode { </span> } side={ - state.otp_key === undefined ? <button - - onClick={(e) => { - setState((s) => ({ ...s, otp_key: "" })); - }} - class="button">change key</button> : + state.otp_key === undefined ? ( + <button + onClick={(e) => { + setState((s) => ({ ...s, otp_key: "" })); + }} + class="button" + > + change key + </button> + ) : ( <button data-tooltip={i18n.str`generate random secret key`} class="button is-info mr-3" onClick={(e) => { - setState((s) => ({ ...s, otp_key: randomBase32Key() })); + setState((s) => ({ + ...s, + otp_key: randomRfc3548Base32Key(), + })); }} > <i18n.Translate>random</i18n.Translate> </button> + ) } /> </Fragment> - ) : undefined} </FormProvider> + ) : undefined}{" "} + </FormProvider> <div class="buttons is-right mt-5"> {onBack && ( diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx index 94424132b..b709b216c 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/create/CreatePage.tsx @@ -19,8 +19,12 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { + isRfc3548Base32Charset, + randomRfc3548Base32Key, +} from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { Fragment, h, VNode } from "preact"; +import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { AsyncButton } from "../../../../components/exception/AsyncButton.js"; import { @@ -32,7 +36,6 @@ import { InputSelector } from "../../../../components/form/InputSelector.js"; import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; import { useBackendContext } from "../../../../context/backend.js"; import { MerchantBackend } from "../../../../declaration.js"; -import { isBase32RFC3548Charset, randomBase32Key } from "../../../../utils/crypto.js"; type Entity = MerchantBackend.OTP.OtpDeviceAddDetails; @@ -44,7 +47,6 @@ interface Props { const algorithms = [0, 1, 2]; const algorithmsNames = ["off", "30s 8d TOTP-SHA1", "30s 8d eTOTP-SHA1"]; - export function CreatePage({ onCreate, onBack }: Props): VNode { const { i18n } = useTranslationContext(); const backend = useBackendContext(); @@ -54,22 +56,24 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { const [showKey, setShowKey] = useState(false); const errors: FormErrors<Entity> = { - otp_device_id: !state.otp_device_id ? i18n.str`required` + otp_device_id: !state.otp_device_id + ? i18n.str`required` : !/[a-zA-Z0-9]*/.test(state.otp_device_id) ? i18n.str`no valid. only characters and numbers` : undefined, otp_algorithm: !state.otp_algorithm ? i18n.str`required` : undefined, - otp_key: !state.otp_key ? i18n.str`required` : - !isBase32RFC3548Charset(state.otp_key) + otp_key: !state.otp_key + ? i18n.str`required` + : !isRfc3548Base32Charset(state.otp_key) ? i18n.str`just letters and numbers from 2 to 7` : state.otp_key.length !== 32 ? i18n.str`size of the key should be 32` : undefined, - otp_device_description: !state.otp_device_description ? i18n.str`required` + otp_device_description: !state.otp_device_description + ? i18n.str`required` : !/[a-zA-Z0-9]*/.test(state.otp_device_description) ? i18n.str`no valid. only characters and numbers` : undefined, - }; const hasErrors = Object.keys(errors).some( @@ -124,7 +128,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { setShowKey(!showKey); }} addonAfter={ - <span class="icon" > + <span class="icon"> {showKey ? ( <i class="mdi mdi-eye" /> ) : ( @@ -137,7 +141,10 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { data-tooltip={i18n.str`generate random secret key`} class="button is-info mr-3" onClick={(e) => { - setState((s) => ({ ...s, otp_key: randomBase32Key() })); + setState((s) => ({ + ...s, + otp_key: randomRfc3548Base32Key(), + })); }} > <i18n.Translate>random</i18n.Translate> diff --git a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx index b82807cc7..85bb272aa 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/otp_devices/update/UpdatePage.tsx @@ -19,6 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { randomRfc3548Base32Key } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -28,10 +29,9 @@ import { FormProvider, } from "../../../../components/form/FormProvider.js"; import { Input } from "../../../../components/form/Input.js"; -import { MerchantBackend, WithId } from "../../../../declaration.js"; import { InputSelector } from "../../../../components/form/InputSelector.js"; import { InputWithAddon } from "../../../../components/form/InputWithAddon.js"; -import { randomBase32Key } from "../../../../utils/crypto.js"; +import { MerchantBackend, WithId } from "../../../../declaration.js"; type Entity = MerchantBackend.OTP.OtpDevicePatchDetails & WithId; @@ -48,8 +48,7 @@ export function UpdatePage({ device, onUpdate, onBack }: Props): VNode { const [state, setState] = useState<Partial<Entity>>(device); const [showKey, setShowKey] = useState(false); - const errors: FormErrors<Entity> = { - }; + const errors: FormErrors<Entity> = {}; const hasErrors = Object.keys(errors).some( (k) => (errors as any)[k] !== undefined, @@ -106,16 +105,23 @@ export function UpdatePage({ device, onUpdate, onBack }: Props): VNode { label={i18n.str`Device key`} readonly={state.otp_key === undefined} inputType={showKey ? "text" : "password"} - help={state.otp_key === undefined ? "Not modified" : "Be sure to be very hard to guess or use the random generator"} + help={ + state.otp_key === undefined + ? "Not modified" + : "Be sure to be very hard to guess or use the random generator" + } tooltip={i18n.str`Your device need to have exactly the same value`} fromStr={(v) => v.toUpperCase()} addonAfterAction={() => { setShowKey(!showKey); }} addonAfter={ - <span class="icon" onClick={() => { - setShowKey(!showKey); - }}> + <span + class="icon" + onClick={() => { + setShowKey(!showKey); + }} + > {showKey ? ( <i class="mdi mdi-eye" /> ) : ( @@ -124,25 +130,34 @@ export function UpdatePage({ device, onUpdate, onBack }: Props): VNode { </span> } side={ - state.otp_key === undefined ? <button - - onClick={(e) => { - setState((s) => ({ ...s, otp_key: "" })); - }} - class="button">change key</button> : + state.otp_key === undefined ? ( + <button + onClick={(e) => { + setState((s) => ({ ...s, otp_key: "" })); + }} + class="button" + > + change key + </button> + ) : ( <button data-tooltip={i18n.str`generate random secret key`} class="button is-info mr-3" onClick={(e) => { - setState((s) => ({ ...s, otp_key: randomBase32Key() })); + setState((s) => ({ + ...s, + otp_key: randomRfc3548Base32Key(), + })); }} > <i18n.Translate>random</i18n.Translate> </button> + ) } /> </Fragment> - ) : undefined} </FormProvider> + ) : undefined}{" "} + </FormProvider> <div class="buttons is-right mt-5"> {onBack && ( diff --git a/packages/merchant-backoffice-ui/src/utils/crypto.ts b/packages/merchant-backoffice-ui/src/utils/crypto.ts deleted file mode 100644 index 27e6ade02..000000000 --- a/packages/merchant-backoffice-ui/src/utils/crypto.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2021-2023 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -const encTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; -// base32 RFC 3548 -function encodeBase32(data: ArrayBuffer) { - const dataBytes = new Uint8Array(data); - let sb = ""; - const size = data.byteLength; - let bitBuf = 0; - let numBits = 0; - let pos = 0; - while (pos < size || numBits > 0) { - if (pos < size && numBits < 5) { - const d = dataBytes[pos++]; - bitBuf = (bitBuf << 8) | d; - numBits += 8; - } - if (numBits < 5) { - // zero-padding - bitBuf = bitBuf << (5 - numBits); - numBits = 5; - } - const v = (bitBuf >>> (numBits - 5)) & 31; - sb += encTable[v]; - numBits -= 5; - } - return sb; -} - -export function isBase32RFC3548Charset(s: string): boolean { - for (let idx = 0; idx < s.length; idx++) { - const c = s.charAt(idx); - if (encTable.indexOf(c) === -1) return false; - } - return true; -} - -export function randomBase32Key(): string { - var buf = new Uint8Array(20); - window.crypto.getRandomValues(buf); - return encodeBase32(buf); -} diff --git a/packages/taler-harness/src/integrationtests/test-otp.ts b/packages/taler-harness/src/integrationtests/test-otp.ts index d4dee12ad..3636b1f47 100644 --- a/packages/taler-harness/src/integrationtests/test-otp.ts +++ b/packages/taler-harness/src/integrationtests/test-otp.ts @@ -22,10 +22,10 @@ import { Duration, MerchantApiClient, PreparePayResultType, - encodeCrock, - getRandomBytes, + TransactionType, j2s, narrowOpSuccessOrThrow, + randomRfc3548Base32Key, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { GlobalTestState } from "../harness/harness.js"; @@ -48,7 +48,7 @@ export async function runOtpTest(t: GlobalTestState) { otp_algorithm: 1, otp_device_description: "Hello", otp_device_id: "mydevice", - otp_key: encodeCrock(getRandomBytes(16)), + otp_key: randomRfc3548Base32Key(), }); narrowOpSuccessOrThrow(createOtpRes); @@ -109,6 +109,10 @@ export async function runOtpTest(t: GlobalTestState) { ); console.log(j2s(transaction)); + + t.assertTrue(transaction.type === TransactionType.Payment); + t.assertTrue(transaction.posConfirmation != null); + t.assertTrue(transaction.posConfirmation.length > 10); } runOtpTest.suites = ["wallet"]; diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts index a32b730a9..2045a4717 100644 --- a/packages/taler-util/src/index.ts +++ b/packages/taler-util/src/index.ts @@ -2,53 +2,54 @@ import { TalerErrorCode } from "./taler-error-codes.js"; export { TalerErrorCode }; +export * from "./CancellationToken.js"; +export * from "./MerchantApiClient.js"; +export { RequestThrottler } from "./RequestThrottler.js"; +export * from "./ReserveStatus.js"; +export * from "./ReserveTransaction.js"; +export { TaskThrottler } from "./TaskThrottler.js"; export * from "./amounts.js"; export * from "./backup-types.js"; +export * from "./bank-api-client.js"; +export * from "./base64.js"; +export * from "./bitcoin.js"; export * from "./codec.js"; +export * from "./contract-terms.js"; +export * from "./errors.js"; +export { fnutil } from "./fnutils.js"; export * from "./helpers.js"; -export * from "./libtool-version.js"; -export * from "./notifications.js"; -export * from "./payto.js"; -export * from "./ReserveStatus.js"; -export * from "./ReserveTransaction.js"; -export * from "./taler-types.js"; -export * from "./taleruri.js"; -export * from "./time.js"; -export * from "./transactions-types.js"; -export * from "./wallet-types.js"; +export * from "./http-client/bank-conversion.js"; +export * from "./http-client/bank-core.js"; +export * from "./http-client/bank-integration.js"; +export * from "./http-client/bank-revenue.js"; +export * from "./http-client/bank-wire.js"; +export * from "./http-client/exchange.js"; +export * from "./http-client/officer-account.js"; +export * from "./http-client/types.js"; +export * from "./http-status-codes.js"; export * from "./i18n.js"; -export * from "./logging.js"; -export * from "./url.js"; -export { fnutil } from "./fnutils.js"; +export * from "./iban.js"; export * from "./kdf.js"; -export * from "./taler-crypto.js"; -export * from "./http-status-codes.js"; -export * from "./bitcoin.js"; +export * from "./libeufin-api-types.js"; +export * from "./libtool-version.js"; +export * from "./logging.js"; +export * from "./merchant-api-types.js"; export { + crypto_sign_keyPair_fromSeed, randomBytes, secretbox, secretbox_open, - crypto_sign_keyPair_fromSeed, setPRNG, } from "./nacl-fast.js"; -export { RequestThrottler } from "./RequestThrottler.js"; -export { TaskThrottler } from "./TaskThrottler.js"; -export * from "./CancellationToken.js"; -export * from "./contract-terms.js"; -export * from "./base64.js"; -export * from "./merchant-api-types.js"; -export * from "./errors.js"; -export * from "./iban.js"; -export * from "./transaction-test-data.js"; -export * from "./libeufin-api-types.js"; -export * from "./MerchantApiClient.js"; -export * from "./bank-api-client.js"; -export * from "./http-client/bank-core.js"; -export * from "./http-client/exchange.js"; -export * from "./http-client/officer-account.js"; -export * from "./http-client/bank-integration.js"; -export * from "./http-client/bank-revenue.js"; -export * from "./http-client/bank-conversion.js"; -export * from "./http-client/bank-wire.js"; -export * from "./http-client/types.js"; +export * from "./notifications.js"; export * from "./operation.js"; +export * from "./payto.js"; +export * from "./rfc3548.js"; +export * from "./taler-crypto.js"; +export * from "./taler-types.js"; +export * from "./taleruri.js"; +export * from "./time.js"; +export * from "./transaction-test-data.js"; +export * from "./transactions-types.js"; +export * from "./url.js"; +export * from "./wallet-types.js"; diff --git a/packages/auditor-backoffice-ui/src/utils/crypto.ts b/packages/taler-util/src/rfc3548.ts index 27e6ade02..2dd18cdfc 100644 --- a/packages/auditor-backoffice-ui/src/utils/crypto.ts +++ b/packages/taler-util/src/rfc3548.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2021-2023 Taler Systems S.A. + (C) 2024 Taler Systems SA GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -14,14 +14,14 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ +import { getRandomBytes } from "./taler-crypto.js"; const encTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; -// base32 RFC 3548 -function encodeBase32(data: ArrayBuffer) { + +/** + * base32 RFC 3548 + */ +export function encodeRfc3548Base32(data: ArrayBuffer) { const dataBytes = new Uint8Array(data); let sb = ""; const size = data.byteLength; @@ -46,7 +46,7 @@ function encodeBase32(data: ArrayBuffer) { return sb; } -export function isBase32RFC3548Charset(s: string): boolean { +export function isRfc3548Base32Charset(s: string): boolean { for (let idx = 0; idx < s.length; idx++) { const c = s.charAt(idx); if (encTable.indexOf(c) === -1) return false; @@ -54,8 +54,7 @@ export function isBase32RFC3548Charset(s: string): boolean { return true; } -export function randomBase32Key(): string { - var buf = new Uint8Array(20); - window.crypto.getRandomValues(buf); - return encodeBase32(buf); +export function randomRfc3548Base32Key(): string { + const buf = getRandomBytes(20); + return encodeRfc3548Base32(buf); } |