mirror of
https://github.com/quantum5/totp.git
synced 2025-04-24 13:41:58 -04:00
Fix some type issues
This commit is contained in:
parent
bd961a5768
commit
cb79b1729f
|
@ -1,4 +1,4 @@
|
||||||
import React, {HTMLProps, SyntheticEvent, useCallback} from 'react';
|
import {HTMLProps, SyntheticEvent, useCallback} from 'react';
|
||||||
|
|
||||||
type HTMLAnchorProps = Omit<HTMLProps<HTMLAnchorElement>, 'href' | 'onClick'>;
|
type HTMLAnchorProps = Omit<HTMLProps<HTMLAnchorElement>, 'href' | 'onClick'>;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
import {useCallback, useEffect, useMemo, useState} from 'react';
|
||||||
import base32Decode from 'base32-decode';
|
import base32Decode from 'base32-decode';
|
||||||
import {NumberInput, TextInput} from './Input';
|
import {NumberInput, TextInput} from './Input';
|
||||||
import OTPOutput from './OTPOutput';
|
import OTPOutput from './OTPOutput';
|
||||||
|
@ -6,6 +6,7 @@ import Select from './Select';
|
||||||
import Collapsible from './Collapsible';
|
import Collapsible from './Collapsible';
|
||||||
import ActionLink from './ActionLink';
|
import ActionLink from './ActionLink';
|
||||||
import {defaults, serializeState, deserializeState} from './state';
|
import {defaults, serializeState, deserializeState} from './state';
|
||||||
|
import {HashAlgorithm} from './algorithms.tsx';
|
||||||
|
|
||||||
function parseState() {
|
function parseState() {
|
||||||
if (window.location.hash.startsWith('#!')) {
|
if (window.location.hash.startsWith('#!')) {
|
||||||
|
@ -78,7 +79,7 @@ function App() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const setAlgorithm = useCallback(
|
const setAlgorithm = useCallback(
|
||||||
(algorithm: string) => setState((state) => ({...state, algorithm})),
|
(algorithm: HashAlgorithm) => setState((state) => ({...state, algorithm})),
|
||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -107,7 +108,7 @@ function App() {
|
||||||
<div className="totp-settings">
|
<div className="totp-settings">
|
||||||
<TextInput label="Secret key" value={secret} onChange={setSecret}
|
<TextInput label="Secret key" value={secret} onChange={setSecret}
|
||||||
error={!validSecret && 'Secret must be a valid base32-encoded string'}/>
|
error={!validSecret && 'Secret must be a valid base32-encoded string'}/>
|
||||||
<progress class="totp-tick" value={validStep ? remaining : 0} max={validStep ? step : 0}/>
|
<progress className="totp-tick" value={validStep ? remaining : 0} max={validStep ? step : 0}/>
|
||||||
{advanced ?
|
{advanced ?
|
||||||
<ActionLink onClick={hideAdvanced}>Hide advanced options</ActionLink> :
|
<ActionLink onClick={hideAdvanced}>Hide advanced options</ActionLink> :
|
||||||
<ActionLink onClick={showAdvanced}>Show advanced options</ActionLink>}
|
<ActionLink onClick={showAdvanced}>Show advanced options</ActionLink>}
|
||||||
|
@ -124,7 +125,7 @@ function App() {
|
||||||
<button type="button" className="btn btn-secondary" onClick={onReset}>Reset</button>
|
<button type="button" className="btn btn-secondary" onClick={onReset}>Reset</button>
|
||||||
</Collapsible>
|
</Collapsible>
|
||||||
</div>
|
</div>
|
||||||
{valid && <OTPOutput secret={decoded} offset={offset} algorithm={algorithm} digits={digits}/>}
|
{valid && decoded && <OTPOutput secret={decoded} offset={offset} algorithm={algorithm} digits={digits}/>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {ReactNode, useEffect, useId} from 'react';
|
import {ReactNode, useEffect, useId} from 'react';
|
||||||
import {Collapse} from 'bootstrap';
|
import {Collapse} from 'bootstrap';
|
||||||
|
|
||||||
export default function Collapsible({children, show}: { children: ReactNode; show: boolean }) {
|
export default function Collapsible({children, show}: { children: ReactNode; show: boolean }) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useCallback, useEffect, useId, useState} from 'react';
|
import {useCallback, useEffect, useId, useState} from 'react';
|
||||||
import Copy from './copy.svg?react';
|
import Copy from './copy.svg?react';
|
||||||
import {Popover} from 'bootstrap';
|
import {Popover} from 'bootstrap';
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {ReactNode, HTMLProps, useCallback, useId} from 'react';
|
import {ChangeEvent, ReactNode, HTMLProps, useCallback, useId} from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
type CommonProps = {
|
type CommonProps = {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useMemo} from 'react';
|
import {useMemo} from 'react';
|
||||||
import {HOTP, HOTPOptions} from '@otplib/core';
|
import {HOTP, HOTPOptions} from '@otplib/core';
|
||||||
import {createDigest} from '@otplib/plugin-crypto-js';
|
import {createDigest} from '@otplib/plugin-crypto-js';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
@ -20,7 +20,7 @@ function OTPCode({code, delta}: { code: string; delta: number }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function OTPOutput({secret, offset, algorithm, digits}: {
|
export default function OTPOutput({secret, offset, algorithm, digits}: {
|
||||||
secret: string;
|
secret: ArrayBuffer;
|
||||||
offset: number;
|
offset: number;
|
||||||
algorithm: HashAlgorithm;
|
algorithm: HashAlgorithm;
|
||||||
digits: number;
|
digits: number;
|
||||||
|
@ -35,7 +35,12 @@ export default function OTPOutput({secret, offset, algorithm, digits}: {
|
||||||
{[...Array(21).keys()].map((i) => {
|
{[...Array(21).keys()].map((i) => {
|
||||||
const delta = i - 10;
|
const delta = i - 10;
|
||||||
const current = offset + delta;
|
const current = offset + delta;
|
||||||
return <OTPCode key={current} code={otp.generate(secret, current)} delta={delta}/>;
|
return <OTPCode key={current} code={otp.generate(
|
||||||
|
// they really wanted an ArrayBuffer or some similar binary type
|
||||||
|
// but misdeclared the type
|
||||||
|
secret as unknown as string,
|
||||||
|
current,
|
||||||
|
)} delta={delta}/>;
|
||||||
})}
|
})}
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {ChangeEvent, ReactNode, useCallback, useId} from 'react';
|
import {ChangeEvent, ReactNode, useCallback, useId} from 'react';
|
||||||
|
|
||||||
export default function Select<T extends string>({label, options, value, onChange}: {
|
export default function Select<T extends string>({label, options, value, onChange}: {
|
||||||
label: ReactNode;
|
label: ReactNode;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import {ALGORITHMS, HashAlgorithm} from './algorithms.tsx';
|
import {ALGORITHMS, HashAlgorithm} from './algorithms.tsx';
|
||||||
|
|
||||||
export type State = {
|
export type State = {
|
||||||
|
@ -16,7 +15,7 @@ export const defaults: State = {
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export function serializeState(state: State): string {
|
export function serializeState(state: State): string {
|
||||||
const values = ['secret', 'step', 'digits', 'algorithm'].map(
|
const values = (['secret', 'step', 'digits', 'algorithm'] as Array<keyof State>).map(
|
||||||
(key) => state[key] !== defaults[key] ? encodeURIComponent(state[key]) : '',
|
(key) => state[key] !== defaults[key] ? encodeURIComponent(state[key]) : '',
|
||||||
);
|
);
|
||||||
while (values[values.length - 1] === '') {
|
while (values[values.length - 1] === '') {
|
||||||
|
@ -31,6 +30,6 @@ export function deserializeState(data: string): State {
|
||||||
secret: values[0] || defaults.secret,
|
secret: values[0] || defaults.secret,
|
||||||
step: +values[1] || defaults.step,
|
step: +values[1] || defaults.step,
|
||||||
digits: +values[2] || defaults.digits,
|
digits: +values[2] || defaults.digits,
|
||||||
algorithm: ALGORITHMS[values[3]] !== undefined ? values[3] : defaults.algorithm,
|
algorithm: values[3] in ALGORITHMS !== undefined ? values[3] as HashAlgorithm : defaults.algorithm,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue