Use tsx syntax in TOTPView.
This commit is contained in:
parent
e4d749cce0
commit
23cc9b60c9
|
@ -1,119 +0,0 @@
|
|||
import { CopyableInputBox } from "../../../elements/CopyableInputBox";
|
||||
import { DoesNotExistError } from "../../../types/internalErrors";
|
||||
import { Page } from "../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { getTOTPCode } from "../../../api/totp/getTOTPCode";
|
||||
import { getTOTPKeys } from "../../../api/totp/getTOTPKeys";
|
||||
import { makeElement } from "z-makeelement";
|
||||
import { objectToMap } from "../../../utils";
|
||||
import { setErrorText } from "../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
|
||||
export interface TOTPListElement extends HTMLElement {
|
||||
setCode(code: string): void;
|
||||
}
|
||||
|
||||
export class TOTPViewPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
this.refresher = undefined;
|
||||
this.totpListElements = {};
|
||||
}
|
||||
|
||||
refresher: number;
|
||||
totpListElements: Record<string, TOTPListElement>;
|
||||
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
const totpList = makeElement({ tag: "div" });
|
||||
await this.router.setPageContent(
|
||||
makeElement({
|
||||
tag: "div",
|
||||
children: [
|
||||
makeElement({
|
||||
tag: "button",
|
||||
text: i18next.t("totp_view_new_btn"),
|
||||
class: ["uk-button", "uk-button-primary", "uk-margin-bottom"],
|
||||
onclick: async () => {
|
||||
await this.router.changePage("NEW_TOTP");
|
||||
},
|
||||
}),
|
||||
makeElement({
|
||||
tag: "p",
|
||||
id: "loadingText",
|
||||
text: i18next.t("totp_view_loading"),
|
||||
}),
|
||||
makeElement({ tag: "br" }),
|
||||
makeElement({ tag: "br" }),
|
||||
totpList,
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
try {
|
||||
const res = await getTOTPKeys(this.state.baseMount);
|
||||
for (const totpKeyName of res) {
|
||||
const totpListElement = this.makeTOTPListElement(totpKeyName);
|
||||
totpList.appendChild(totpListElement);
|
||||
this.totpListElements[totpKeyName] = totpListElement;
|
||||
await this.updateTOTPElement(totpKeyName, totpListElement);
|
||||
}
|
||||
document.getElementById("loadingText").remove();
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
if (error == DoesNotExistError) {
|
||||
const loadingText = document.getElementById("loadingText");
|
||||
loadingText.innerText = i18next.t("totp_view_empty");
|
||||
} else {
|
||||
setErrorText(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
const totpRefresher = async () => {
|
||||
await Promise.all(
|
||||
Array.from(objectToMap(this.totpListElements)).map((kv: [string, TOTPListElement]) => {
|
||||
return this.updateTOTPElement(...kv);
|
||||
}),
|
||||
);
|
||||
};
|
||||
await totpRefresher();
|
||||
this.refresher = setInterval(async () => {
|
||||
await totpRefresher();
|
||||
}, 3000) as unknown as number;
|
||||
}
|
||||
|
||||
async cleanup(): Promise<void> {
|
||||
clearInterval(this.refresher);
|
||||
this.totpListElements = {};
|
||||
}
|
||||
|
||||
async updateTOTPElement(totpKeyName: string, totpListElement: TOTPListElement): Promise<void> {
|
||||
totpListElement.setCode(await getTOTPCode(this.state.baseMount, totpKeyName));
|
||||
}
|
||||
|
||||
makeTOTPListElement(totpKeyName: string): TOTPListElement {
|
||||
const totpKeyBox = CopyableInputBox(totpKeyName, false);
|
||||
const totpValueBox = CopyableInputBox(i18next.t("totp_view_loading_box"));
|
||||
|
||||
const gridElement = makeElement({
|
||||
tag: "div",
|
||||
class: ["uk-grid", "uk-grid-small", "uk-text-expand"],
|
||||
children: [totpKeyBox, totpValueBox],
|
||||
}) as TOTPListElement;
|
||||
|
||||
gridElement.setCode = (code: string) => totpValueBox.setText(code);
|
||||
|
||||
return gridElement;
|
||||
}
|
||||
|
||||
async getPageTitle(): Promise<Element | string> {
|
||||
return await SecretTitleElement(this.router);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("totp_view_title");
|
||||
}
|
||||
}
|
128
src/pages/Secrets/TOTP/TOTPView.tsx
Normal file
128
src/pages/Secrets/TOTP/TOTPView.tsx
Normal file
|
@ -0,0 +1,128 @@
|
|||
import { CopyableInputBox } from "../../../elements/ReactCopyableInputBox";
|
||||
import { DoesNotExistError } from "../../../types/internalErrors";
|
||||
import { Page } from "../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { getTOTPCode } from "../../../api/totp/getTOTPCode";
|
||||
import { getTOTPKeys } from "../../../api/totp/getTOTPKeys";
|
||||
import { makeElement } from "z-makeelement";
|
||||
import { objectToMap } from "../../../utils";
|
||||
import { setErrorText } from "../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
import { render, JSX } from "preact";
|
||||
|
||||
export interface TOTPListElement extends HTMLElement {
|
||||
setCode(code: string): void;
|
||||
}
|
||||
|
||||
function quickHash(str: string): string {
|
||||
var hash = 0;
|
||||
if (str.length == 0) {
|
||||
return String(hash).toString();
|
||||
}
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash;
|
||||
}
|
||||
return String(hash).toString();
|
||||
}
|
||||
|
||||
|
||||
export function TOTPGridItem(props: { item_key: string, item_value: string }): JSX.Element {
|
||||
return (
|
||||
<div class="uk-grid uk-grid-small uk-text-left" uk-grid>
|
||||
<CopyableInputBox text={props.item_key} copyable />
|
||||
<CopyableInputBox text={props.item_value} copyable />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export class TOTPViewPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
this.refresher = undefined;
|
||||
}
|
||||
|
||||
refresher: number;
|
||||
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
console.log(quickHash("abc"));
|
||||
|
||||
render((
|
||||
<div>
|
||||
<button
|
||||
class="uk-button uk-button-primary uk-margin-bottom"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("NEW_TOTP");
|
||||
}}>
|
||||
{i18next.t("totp_view_new_btn")}
|
||||
</button>
|
||||
<p id="loadingText">{i18next.t("totp_view_loading")}</p>
|
||||
<br />
|
||||
<br />
|
||||
<div id="totpList"></div>
|
||||
</div>
|
||||
), this.router.pageContentElement)
|
||||
|
||||
try {
|
||||
await this.updateTOTPElements();
|
||||
document.getElementById("loadingText").remove();
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
if (error == DoesNotExistError) {
|
||||
const loadingText = document.getElementById("loadingText");
|
||||
loadingText.innerText = i18next.t("totp_view_empty");
|
||||
} else {
|
||||
setErrorText(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
const totpRefresher = async () => {
|
||||
await this.updateTOTPElements();
|
||||
};
|
||||
|
||||
this.refresher = setInterval(async () => {
|
||||
await totpRefresher();
|
||||
}, 3000) as unknown as number;
|
||||
}
|
||||
|
||||
async cleanup(): Promise<void> {
|
||||
clearInterval(this.refresher);
|
||||
}
|
||||
|
||||
async updateTOTPElements(): Promise<void> {
|
||||
render((
|
||||
<>
|
||||
{await Promise.all(Array.from(await getTOTPKeys(this.state.baseMount)).map(async (key) =>
|
||||
<TOTPGridItem
|
||||
item_key={String(key).toString()}
|
||||
item_value={await getTOTPCode(this.state.baseMount, key)}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
), document.querySelector("#totpList"))
|
||||
}
|
||||
|
||||
makeTOTPListElement(totpKeyName: string): TOTPListElement {
|
||||
|
||||
const gridElement = makeElement({
|
||||
tag: "div",
|
||||
class: ["uk-grid", "uk-grid-small", "uk-text-expand"],
|
||||
}) as TOTPListElement;
|
||||
|
||||
|
||||
return gridElement;
|
||||
}
|
||||
|
||||
async getPageTitle(): Promise<Element | string> {
|
||||
return await SecretTitleElement(this.router);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("totp_view_title");
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue