1
0
Fork 0

Rework PageRouter, Page, pageContent and SecretTitleElement.

This commit is contained in:
Kitteh 2021-05-15 10:54:39 +01:00
parent 8f448b80fc
commit 67bd89db1a
36 changed files with 515 additions and 532 deletions

View file

@ -1,4 +1,4 @@
import { Page } from "./types/Page";
import { Page } from "./PageSystem/Page";
import { allPages } from "./allPages";
import { getKeyByObjectPropertyValue } from "./utils";

29
src/PageSystem/Page.ts Normal file
View file

@ -0,0 +1,29 @@
import { PageRouter } from "./PageRouter";
import { PageState } from "../PageState";
export class Page {
constructor() {
// Do Nothing
}
public router: PageRouter;
public state: PageState;
async render(): Promise<void> {}
get name(): string {
return "Page";
}
async getPageTitle(): Promise<Element | string> {
return this.name;
}
async goBack(): Promise<void> {
await this.router.changePage("HOME");
}
async cleanup(): Promise<void> {
// Do Nothing
}
async setRouterAndState(router: PageRouter, state: PageState): Promise<void> {
this.router = router;
this.state = state;
}
}

View file

@ -1,5 +1,6 @@
import { Page } from "./types/Page";
import { getObjectKeys } from "./utils";
import { Page } from "./Page";
import { PageState } from "../PageState";
import { getObjectKeys } from "../utils";
type pageList = {
[key: string]: Page;
@ -9,9 +10,15 @@ const PageDoesNotExistError = new Error("Page does not exist.");
const PageHasNotBeenSetError = new Error("Page has not been set.");
export class PageRouter extends EventTarget {
constructor(pages: pageList, pageContentElement: HTMLElement, pageTitleElement: HTMLElement) {
constructor(
pages: pageList,
state: PageState,
pageContentElement: HTMLElement,
pageTitleElement: HTMLElement,
) {
super();
this.pages = pages;
this.state = state;
this.pageContentElement = pageContentElement;
this.pageTitleElement = pageTitleElement;
}
@ -20,6 +27,7 @@ export class PageRouter extends EventTarget {
private currentPageID: string;
private currentPage: Page;
public state: PageState;
public pageContentElement: HTMLElement;
public pageTitleElement: HTMLElement;
@ -27,10 +35,23 @@ export class PageRouter extends EventTarget {
return getObjectKeys(this.pages);
}
public async getCurrentPage(): Promise<Page> {
return this.currentPage;
}
public async getCurrentPageID(): Promise<string> {
return this.currentPageID;
}
public async setPageContent(content: string | HTMLElement): Promise<void> {
if (typeof content === "string") {
this.pageContentElement.innerHTML = content;
} else {
this.pageContentElement.innerHTML = "";
this.pageContentElement.appendChild(content);
}
}
public async changePage(pageID: string): Promise<void> {
if (!(await this.getPageIDs()).includes(pageID)) throw PageDoesNotExistError;
@ -43,6 +64,8 @@ export class PageRouter extends EventTarget {
this.currentPageID = pageID;
this.currentPage = this.pages[pageID];
await this.currentPage.setRouterAndState(this, this.state);
// Dispatch an event saying the page has been changed.
this.dispatchEvent(new CustomEvent("pageChanged"));
@ -57,8 +80,12 @@ export class PageRouter extends EventTarget {
this.pageContentElement.innerHTML = "";
this.pageTitleElement.innerHTML = "";
// TODO: Make Page have a getTitle method.
this.pageTitleElement.innerText = this.currentPage.name;
const pageTitle = await this.currentPage.getPageTitle();
if (typeof pageTitle === "string") {
this.pageTitleElement.innerText = pageTitle;
} else {
this.pageTitleElement.appendChild(pageTitle);
}
await this.currentPage.render();
}

View file

@ -13,7 +13,7 @@ import { NewTOTPEnginePage } from "./pages/NewEngines/NewTOTPEngine";
import { NewTOTPPage } from "./pages/TOTP/NewTOTP";
import { NewTransitEnginePage } from "./pages/NewEngines/NewTransitEngine";
import { NewTransitKeyPage } from "./pages/Transit/NewTransitKey";
import { Page } from "./types/Page";
import { Page } from "./PageSystem/Page";
import { PwGenPage } from "./pages/PwGen";
import { SetLanguagePage } from "./pages/SetLanguage";
import { SetVaultURLPage } from "./pages/SetVaultURL";

View file

@ -1,9 +1,9 @@
import { ListItem } from "./ListItem";
import { makeElement } from "../htmlUtils";
import { pageRouter } from "../globalPageRouter";
import i18next from "i18next";
import { PageRouter } from "../PageSystem/PageRouter";
export function NavBar(): HTMLElement {
export function NavBar(router: PageRouter): HTMLElement {
return makeElement({
id: "navBar",
tag: "nav",
@ -21,7 +21,7 @@ export function NavBar(): HTMLElement {
tag: "a",
text: i18next.t("home_btn"),
onclick: async () => {
await pageRouter.changePage("HOME");
await router.changePage("HOME");
},
}),
),
@ -30,7 +30,7 @@ export function NavBar(): HTMLElement {
tag: "a",
text: i18next.t("back_btn"),
onclick: async () => {
await pageRouter.goBack();
await router.goBack();
},
}),
),
@ -39,7 +39,7 @@ export function NavBar(): HTMLElement {
tag: "a",
text: i18next.t("refresh_btn"),
onclick: async () => {
await pageRouter.refresh();
await router.refresh();
},
}),
),
@ -58,7 +58,7 @@ export function NavBar(): HTMLElement {
tag: "a",
text: i18next.t("me_btn"),
onclick: async () => {
await pageRouter.changePage("ME");
await router.changePage("ME");
},
}),
),
@ -69,6 +69,6 @@ export function NavBar(): HTMLElement {
});
}
export function reloadNavBar(): void {
document.querySelector("#navBar").replaceWith(NavBar());
export function reloadNavBar(router: PageRouter): void {
document.querySelector("#navBar").replaceWith(NavBar(router));
}

View file

@ -0,0 +1,57 @@
import { PageRouter } from "../PageSystem/PageRouter";
import { makeElement } from "../htmlUtils";
function currentTitleSecretText(router: PageRouter, suffix = ""): string {
let currentSecretText = router.state.currentSecret;
currentSecretText += suffix;
if (router.state.currentSecretVersion !== null)
currentSecretText += ` (v${router.state.currentSecretVersion})`;
return currentSecretText;
}
export async function SecretTitleElement(router: PageRouter, suffix = ""): Promise<HTMLElement> {
const titleElement = makeElement({
tag: "div",
children: [
makeElement({
tag: "a",
text: router.state.currentBaseMount + " ",
onclick: async () => {
router.state.currentSecretPath = [];
router.state.currentSecret = "";
router.state.currentSecretVersion = null;
if (
router.state.currentMountType.startsWith("kv") ||
router.state.currentMountType == "cubbyhole"
) {
await router.changePage("KEY_VALUE_VIEW");
} else if (router.state.currentMountType == "totp") {
await router.changePage("TOTP");
} else if (router.state.currentMountType == "transit") {
await router.changePage("TRANSIT_VIEW");
}
},
}),
...router.state.currentSecretPath.map((secretPath, index, secretPaths) => {
return makeElement({
tag: "a",
text: secretPath + " ",
onclick: async () => {
router.state.currentSecretVersion = null;
if (router.state.currentMountType.startsWith("kv")) {
router.state.currentSecretPath = secretPaths.slice(0, index + 1);
await router.changePage("KEY_VALUE_VIEW");
}
},
});
}),
makeElement({
tag: "span",
condition: router.state.currentSecret.length != 0,
text: currentTitleSecretText(router, suffix),
}),
],
});
return titleElement;
}

View file

@ -1,6 +0,0 @@
import { PageRouter } from "./PageRouter";
export let pageRouter: PageRouter;
export function setPageRouter(router: PageRouter): void {
pageRouter = router;
}

View file

@ -20,14 +20,13 @@ Prism.highlightAll();
// Actual Imports
import { NavBar } from "./elements/NavBar";
import { PageRouter } from "./PageRouter";
import { PageRouter } from "./PageSystem/PageRouter";
import { allPages } from "./allPages";
import { formatDistance } from "./formatDistance";
import { getSealStatus } from "./api/sys/getSealStatus";
import { makeElement } from "./htmlUtils";
import { pageState } from "./globalPageState";
import { playground } from "./playground";
import { setPageRouter } from "./globalPageRouter";
import i18next from "i18next";
// @ts-ignore
@ -41,7 +40,7 @@ declare global {
async function onLoad(): Promise<void> {
document.body.innerHTML = "";
document.body.appendChild(NavBar());
document.body.appendChild(makeElement({tag: "div", id: "navBarReplace"}));
document.body.appendChild(
makeElement({
tag: "div",
@ -69,10 +68,12 @@ async function onLoad(): Promise<void> {
const pageRouter = new PageRouter(
allPages,
pageState,
document.getElementById("pageContent"),
document.getElementById("pageTitle"),
);
setPageRouter(pageRouter);
document.querySelector("#navBarReplace").replaceWith(NavBar(pageRouter));
pageRouter.addEventListener("pageChanged", async function (_) {
pageState.currentPage = await pageRouter.getCurrentPageID();
@ -80,7 +81,7 @@ async function onLoad(): Promise<void> {
});
if (process.env.NODE_ENV == "development") {
await playground();
await playground(pageRouter);
}
await pageRouter.changePage(pageState.currentPageString);

View file

@ -1,41 +1,37 @@
import { Page } from "./types/Page";
import { PageState } from "./PageState";
import { PageRouter } from "./PageSystem/PageRouter";
import { getSealStatus } from "./api/sys/getSealStatus";
import { lookupSelf } from "./api/sys/lookupSelf";
import { makeElement } from "./htmlUtils";
import { pageRouter } from "./globalPageRouter";
import { pageState } from "./globalPageState";
import ClipboardJS from "clipboard";
import UIkit from "uikit";
import i18next from "i18next";
async function prePageChecksReal() {
if (pageState.language.length == 0) {
await changePage("SET_LANGUAGE");
async function prePageChecksReal(router: PageRouter) {
if (router.state.language.length == 0) {
await router.changePage("SET_LANGUAGE");
throw new Error("Language Not Set");
}
if (!pageState.apiURL) {
await changePage("SET_VAULT_URL");
if (!router.state.apiURL) {
await router.changePage("SET_VAULT_URL");
throw new Error("Vault URL Not Set");
}
const sealStatus = await getSealStatus();
if (sealStatus.sealed) {
await changePage("UNSEAL");
await router.changePage("UNSEAL");
throw new Error("Vault Sealed");
}
try {
await lookupSelf();
} catch (e) {
await changePage("LOGIN");
await router.changePage("LOGIN");
throw e;
}
}
export async function prePageChecks(): Promise<boolean> {
export async function prePageChecks(router: PageRouter): Promise<boolean> {
try {
await prePageChecksReal();
await prePageChecksReal(router);
} catch (e) {
console.log("OHNO", e);
return false;
@ -78,82 +74,3 @@ export function setErrorText(text: string): void {
timeout: 2000,
});
}
export async function changePage(page: string): Promise<void> {
await pageRouter.changePage(page);
}
export function setPageTitle(title: string | HTMLElement): void {
const pageTitle = document.getElementById("pageTitle");
pageTitle.innerHTML = "";
if (typeof title === "string") {
pageTitle.innerText = title.toString();
} else {
pageTitle.appendChild(title);
}
}
function currentTitleSecretText() {
let currentSecretText = pageState.currentSecret;
currentSecretText += (pageState.currentPage as Page).titleSuffix;
if (pageState.currentSecretVersion !== null)
currentSecretText += ` (v${pageState.currentSecretVersion})`;
return currentSecretText;
}
export function setTitleElement(pageState: PageState): void {
const titleElement = makeElement({
tag: "div",
children: [
makeElement({
tag: "a",
text: pageState.currentBaseMount + " ",
onclick: async () => {
pageState.currentSecretPath = [];
pageState.currentSecret = "";
pageState.currentSecretVersion = null;
if (
pageState.currentMountType.startsWith("kv") ||
pageState.currentMountType == "cubbyhole"
) {
await changePage("KEY_VALUE_VIEW");
} else if (pageState.currentMountType == "totp") {
await changePage("TOTP");
} else if (pageState.currentMountType == "transit") {
await changePage("TRANSIT_VIEW");
}
},
}),
...pageState.currentSecretPath.map(function (secretPath, index, secretPaths) {
return makeElement({
tag: "a",
text: secretPath + " ",
onclick: async () => {
pageState.currentSecretVersion = null;
if (pageState.currentMountType.startsWith("kv")) {
pageState.currentSecretPath = secretPaths.slice(0, index + 1);
await changePage("KEY_VALUE_VIEW");
}
},
});
}),
makeElement({
tag: "span",
condition: pageState.currentSecret.length != 0,
text: currentTitleSecretText(),
}),
],
});
setPageTitle(titleElement);
}
export function setPageContent(content: string | HTMLElement): void {
const pageContent = document.getElementById("pageContent");
if (typeof content === "string") {
pageContent.innerHTML = content;
} else {
pageContent.innerHTML = "";
pageContent.appendChild(content);
}
}

View file

@ -1,10 +1,9 @@
import { MountType, getMounts } from "../api/sys/getMounts";
import { Page } from "../types/Page";
import { changePage, prePageChecks, setErrorText, setPageContent } from "../pageUtils";
import { Page } from "../PageSystem/Page";
import { getCapabilitiesPath } from "../api/sys/getCapabilities";
import { lookupSelf } from "../api/sys/lookupSelf";
import { makeElement } from "../htmlUtils";
import { pageState } from "../globalPageState";
import { prePageChecks, setErrorText } from "../pageUtils";
import { sortedObjectMap } from "../utils";
import i18next from "i18next";
@ -13,11 +12,11 @@ export class HomePage extends Page {
super();
}
async render(): Promise<void> {
setPageContent("");
if (!(await prePageChecks())) return;
await this.router.setPageContent("");
if (!(await prePageChecks(this.router))) return;
const homePageContent = makeElement({ tag: "div" });
setPageContent(homePageContent);
await this.router.setPageContent(homePageContent);
const textList = makeElement({
tag: "ul",
class: "uk-nav",
@ -26,7 +25,7 @@ export class HomePage extends Page {
tag: "li",
children: makeElement({
tag: "span",
html: i18next.t("vaulturl_text", { text: pageState.apiURL }),
html: i18next.t("vaulturl_text", { text: this.state.apiURL }),
}),
}),
makeElement({
@ -35,7 +34,7 @@ export class HomePage extends Page {
tag: "a",
text: i18next.t("password_generator_btn"),
onclick: async () => {
await changePage("PW_GEN");
await this.router.changePage("PW_GEN");
},
}),
}),
@ -57,8 +56,8 @@ export class HomePage extends Page {
const error = e as Error;
setErrorText(error.message);
if (error.message == "permission denied") {
pageState.token = "";
await changePage("LOGIN");
this.state.token = "";
await this.router.changePage("LOGIN");
}
}
@ -70,16 +69,16 @@ export class HomePage extends Page {
text: i18next.t("home_new_secrets_engine_button"),
class: ["uk-button", "uk-button-primary", "uk-margin-top"],
onclick: async () => {
await changePage("NEW_SECRETS_ENGINE");
await this.router.changePage("NEW_SECRETS_ENGINE");
},
}),
);
}
pageState.currentBaseMount = "";
pageState.currentSecretPath = [];
pageState.currentSecret = "";
pageState.currentSecretVersion = null;
this.state.currentBaseMount = "";
this.state.currentSecretPath = [];
this.state.currentSecret = "";
this.state.currentSecretVersion = null;
const navList = makeElement({
tag: "ul",
@ -91,7 +90,7 @@ export class HomePage extends Page {
// sort it by secretPath so it's in alphabetical order consistantly.
const mountsMap = sortedObjectMap(mounts);
mountsMap.forEach(function (mount: MountType, baseMount) {
mountsMap.forEach((mount: MountType, baseMount) => {
if (typeof mount != "object") return;
if (mount == null) return;
if (!("type" in mount)) return;
@ -122,9 +121,9 @@ export class HomePage extends Page {
tag: "a",
text: linkText,
onclick: async () => {
pageState.currentBaseMount = baseMount;
pageState.currentMountType = mountType;
await changePage(linkPage);
this.state.currentBaseMount = baseMount;
this.state.currentMountType = mountType;
await this.router.changePage(linkPage);
},
}),
}),

View file

@ -1,8 +1,7 @@
import { Page } from "../../types/Page";
import { changePage, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { deleteSecret } from "../../api/kv/deleteSecret";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import i18next from "i18next";
export class KeyValueDeletePage extends Page {
@ -10,17 +9,16 @@ export class KeyValueDeletePage extends Page {
super();
}
async goBack(): Promise<void> {
if (pageState.currentSecretVersion != null) {
pageState.currentSecretVersion = null;
await changePage("KEY_VALUE_SECRET");
if (this.state.currentSecretVersion != null) {
this.state.currentSecretVersion = null;
await this.router.changePage("KEY_VALUE_SECRET");
} else {
pageState.currentSecret = "";
await changePage("KEY_VALUE_VIEW");
this.state.currentSecret = "";
await this.router.changePage("KEY_VALUE_VIEW");
}
}
async render(): Promise<void> {
setTitleElement(pageState);
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
children: [
@ -34,11 +32,11 @@ export class KeyValueDeletePage extends Page {
text: i18next.t("kv_delete_btn"),
onclick: () => {
void deleteSecret(
pageState.currentBaseMount,
pageState.currentMountType,
pageState.currentSecretPath,
pageState.currentSecret,
pageState.currentSecretVersion,
this.state.currentBaseMount,
this.state.currentMountType,
this.state.currentSecretPath,
this.state.currentSecret,
this.state.currentSecretVersion,
).then(() => {
void this.goBack();
});
@ -48,9 +46,11 @@ export class KeyValueDeletePage extends Page {
}),
);
}
get titleSuffix(): string {
return i18next.t("kv_delete_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("kv_delete_suffix"));
}
get name(): string {
return i18next.t("kv_delete_title");
}

View file

@ -1,8 +1,8 @@
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { createOrUpdateSecret } from "../../api/kv/createOrUpdateSecret";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
export class KeyValueNewPage extends Page {
@ -11,13 +11,12 @@ export class KeyValueNewPage extends Page {
}
async goBack(): Promise<void> {
await changePage("KEY_VALUE_VIEW");
await this.router.changePage("KEY_VALUE_VIEW");
}
addKVNewForm: HTMLFormElement;
async render(): Promise<void> {
setTitleElement(pageState);
this.addKVNewForm = makeElement({
tag: "form",
id: "addKVNewForm",
@ -51,7 +50,7 @@ export class KeyValueNewPage extends Page {
}),
],
}) as HTMLFormElement;
setPageContent(this.addKVNewForm);
await this.router.setPageContent(this.addKVNewForm);
this.addKVNewForm.addEventListener("submit", async (e: Event) => {
e.preventDefault();
@ -64,27 +63,27 @@ export class KeyValueNewPage extends Page {
const path = formData.get("path") as string;
let keyData = {};
if (["kv-v1", "cubbyhole"].includes(pageState.currentMountType)) {
if (["kv-v1", "cubbyhole"].includes(this.state.currentMountType)) {
keyData = { key: "value" };
}
try {
await createOrUpdateSecret(
pageState.currentBaseMount,
pageState.currentMountType,
pageState.currentSecretPath,
this.state.currentBaseMount,
this.state.currentMountType,
this.state.currentSecretPath,
path,
keyData,
);
await changePage("KEY_VALUE_VIEW");
await this.router.changePage("KEY_VALUE_VIEW");
} catch (e: unknown) {
const error = e as Error;
setErrorText(error.message);
}
}
get titleSuffix(): string {
return i18next.t("kv_new_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("kv_new_suffix"));
}
get name(): string {

View file

@ -1,10 +1,9 @@
import { CopyableInputBox } from "../../elements/CopyableInputBox";
import { Page } from "../../types/Page";
import { changePage, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { getCapabilities } from "../../api/sys/getCapabilities";
import { getSecret } from "../../api/kv/getSecret";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import { sortedObjectMap } from "../../utils";
import { undeleteSecret } from "../../api/kv/undeleteSecret";
import Prism from "prismjs";
@ -15,17 +14,16 @@ export class KeyValueSecretPage extends Page {
super();
}
async goBack(): Promise<void> {
if (pageState.currentSecretVersion != null) {
pageState.currentSecretVersion = null;
await changePage("KEY_VALUE_VERSIONS");
if (this.state.currentSecretVersion != null) {
this.state.currentSecretVersion = null;
await this.router.changePage("KEY_VALUE_VERSIONS");
} else {
pageState.currentSecret = "";
await changePage("KEY_VALUE_VIEW");
this.state.currentSecret = "";
await this.router.changePage("KEY_VALUE_VIEW");
}
}
async render(): Promise<void> {
setTitleElement(pageState);
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
children: [
@ -50,17 +48,20 @@ export class KeyValueSecretPage extends Page {
const kvList = document.querySelector("#kvList");
let isSecretNestedJson = false;
const caps = await getCapabilities(
pageState.currentBaseMount,
pageState.currentSecretPath,
pageState.currentSecret,
this.state.currentBaseMount,
this.state.currentSecretPath,
this.state.currentSecret,
);
if (caps.includes("delete")) {
let deleteButtonText = i18next.t("kv_secret_delete_btn");
if (pageState.currentMountType == "kv-v2" && pageState.currentSecretVersion == null) {
if (this.state.currentMountType == "kv-v2" && this.state.currentSecretVersion == null) {
deleteButtonText = i18next.t("kv_secret_delete_all_btn");
} else if (pageState.currentMountType == "kv-v2" && pageState.currentSecretVersion != null) {
} else if (
this.state.currentMountType == "kv-v2" &&
this.state.currentSecretVersion != null
) {
deleteButtonText = i18next.t("kv_secret_delete_version_btn", {
version: pageState.currentSecretVersion,
version: this.state.currentSecretVersion,
});
}
buttonsBlock.appendChild(
@ -69,107 +70,105 @@ export class KeyValueSecretPage extends Page {
id: "deleteButton",
class: ["uk-button", "uk-button-danger"],
onclick: async () => {
await changePage("KEY_VALUE_DELETE");
await this.router.changePage("KEY_VALUE_DELETE");
},
text: deleteButtonText,
}),
);
}
if (caps.includes("update")) {
if (pageState.currentSecretVersion == null) {
if (this.state.currentSecretVersion == null) {
buttonsBlock.appendChild(
makeElement({
tag: "button",
id: "editButton",
class: ["uk-button", "uk-margin", "uk-button-primary"],
onclick: async () => {
await changePage("KEY_VALUE_SECRET_EDIT");
await this.router.changePage("KEY_VALUE_SECRET_EDIT");
},
text: i18next.t("kv_secret_edit_btn"),
}),
);
}
}
if (pageState.currentMountType == "kv-v2") {
if (this.state.currentMountType == "kv-v2") {
buttonsBlock.appendChild(
makeElement({
tag: "button",
id: "versionsButton",
class: ["uk-button", "uk-button-secondary"],
onclick: async () => {
await changePage("KEY_VALUE_VERSIONS");
await this.router.changePage("KEY_VALUE_VERSIONS");
},
text: i18next.t("kv_secret_versions_btn"),
}),
);
}
void getSecret(
pageState.currentBaseMount,
pageState.currentMountType,
pageState.currentSecretPath,
pageState.currentSecret,
pageState.currentSecretVersion,
).then((secretInfo) => {
if (secretInfo == null && pageState.currentMountType == "kv-v2") {
document.querySelector("#buttonsBlock").remove();
document.getElementById("loadingText").remove();
kvList.appendChild(
makeElement({
tag: "p",
text: i18next.t("kv_secret_deleted_text"),
}),
);
kvList.appendChild(
makeElement({
tag: "button",
text: i18next.t("kv_secret_restore_btn"),
id: "restoreButton",
class: ["uk-button", "uk-button-primary"],
onclick: () => {
void undeleteSecret(
pageState.currentBaseMount,
pageState.currentSecretPath,
pageState.currentSecret,
pageState.currentSecretVersion,
).then((_) => {
void changePage(pageState.currentPageString);
});
},
}),
);
return;
}
const secretsMap = sortedObjectMap(secretInfo);
for (const value of secretsMap.values()) {
if (typeof value == "object") isSecretNestedJson = true;
}
if (isSecretNestedJson) {
const jsonText = JSON.stringify(
sortedObjectMap(secretsMap as unknown as Record<string, unknown>),
null,
4,
);
kvList.appendChild(
makeElement({
tag: "pre",
class: ["code-block", "language-json", "line-numbers"],
html: Prism.highlight(jsonText, Prism.languages.json, "json"),
}),
);
} else {
secretsMap.forEach((value: string, key: string) => {
const kvListElement = this.makeKVListElement(key, value);
kvList.appendChild(kvListElement);
}, this);
}
const secretInfo = await getSecret(
this.state.currentBaseMount,
this.state.currentMountType,
this.state.currentSecretPath,
this.state.currentSecret,
this.state.currentSecretVersion,
);
if (secretInfo == null && this.state.currentMountType == "kv-v2") {
document.querySelector("#buttonsBlock").remove();
document.getElementById("loadingText").remove();
});
kvList.appendChild(
makeElement({
tag: "p",
text: i18next.t("kv_secret_deleted_text"),
}),
);
kvList.appendChild(
makeElement({
tag: "button",
text: i18next.t("kv_secret_restore_btn"),
id: "restoreButton",
class: ["uk-button", "uk-button-primary"],
onclick: async () => {
await undeleteSecret(
this.state.currentBaseMount,
this.state.currentSecretPath,
this.state.currentSecret,
this.state.currentSecretVersion,
);
await this.router.changePage(this.state.currentPageString);
},
}),
);
return;
}
const secretsMap = sortedObjectMap(secretInfo);
for (const value of secretsMap.values()) {
if (typeof value == "object") isSecretNestedJson = true;
}
if (isSecretNestedJson) {
const jsonText = JSON.stringify(
sortedObjectMap(secretsMap as unknown as Record<string, unknown>),
null,
4,
);
kvList.appendChild(
makeElement({
tag: "pre",
class: ["code-block", "language-json", "line-numbers"],
html: Prism.highlight(jsonText, Prism.languages.json, "json"),
}),
);
} else {
secretsMap.forEach((value: string, key: string) => {
const kvListElement = this.makeKVListElement(key, value);
kvList.appendChild(kvListElement);
}, this);
}
document.getElementById("loadingText").remove();
}
makeKVListElement(key: string, value: string): HTMLElement {
return makeElement({
@ -179,6 +178,10 @@ export class KeyValueSecretPage extends Page {
});
}
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router);
}
get name(): string {
return i18next.t("kv_secret_title");
}

View file

@ -1,10 +1,10 @@
import { CodeJar } from "codejar";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { createOrUpdateSecret } from "../../api/kv/createOrUpdateSecret";
import { getSecret } from "../../api/kv/getSecret";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import { sortedObjectMap, verifyJSONString } from "../../utils";
import i18next from "i18next";
@ -13,10 +13,9 @@ export class KeyValueSecretEditPage extends Page {
super();
}
async goBack(): Promise<void> {
await changePage("KEY_VALUE_SECRET");
await this.router.changePage("KEY_VALUE_SECRET");
}
async render(): Promise<void> {
setTitleElement(pageState);
const loadingText = makeElement({
tag: "p",
text: i18next.t("kv_sec_edit_loading"),
@ -30,7 +29,7 @@ export class KeyValueSecretEditPage extends Page {
class: ["uk-button", "uk-button-primary"],
text: i18next.t("kv_sec_edit_btn"),
});
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
children: [
@ -45,44 +44,43 @@ export class KeyValueSecretEditPage extends Page {
],
}),
);
void getSecret(
pageState.currentBaseMount,
pageState.currentMountType,
pageState.currentSecretPath,
pageState.currentSecret,
).then((secretInfo) => {
loadingText.remove();
const secretInfo = await getSecret(
this.state.currentBaseMount,
this.state.currentMountType,
this.state.currentSecretPath,
this.state.currentSecret,
);
const secretsJSON = JSON.stringify(sortedObjectMap(secretInfo), null, 4);
loadingText.remove();
const jar = CodeJar(editor, () => {}, { tab: " ".repeat(4) });
jar.updateCode(secretsJSON);
saveButton.onclick = function () {
if (!verifyJSONString(jar.toString())) {
setErrorText(i18next.t("kv_sec_edit_invalid_json_err"));
return;
}
const secretsJSON = JSON.stringify(sortedObjectMap(secretInfo), null, 4);
createOrUpdateSecret(
pageState.currentBaseMount,
pageState.currentMountType,
pageState.currentSecretPath,
pageState.currentSecret,
const jar = CodeJar(editor, () => {}, { tab: " ".repeat(4) });
jar.updateCode(secretsJSON);
saveButton.onclick = async () => {
if (!verifyJSONString(jar.toString())) {
setErrorText(i18next.t("kv_sec_edit_invalid_json_err"));
return;
}
try {
await createOrUpdateSecret(
this.state.currentBaseMount,
this.state.currentMountType,
this.state.currentSecretPath,
this.state.currentSecret,
JSON.parse(jar.toString()),
)
.then((_) => {
void changePage("KEY_VALUE_SECRET");
return;
})
.catch((e: Error) => {
setErrorText(e.message);
});
};
});
);
await this.router.changePage("KEY_VALUE_SECRET");
} catch (e: unknown) {
const error = e as Error;
setErrorText(error.message);
}
};
}
get titleSuffix(): string {
return i18next.t("kv_sec_edit_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("kv_sec_edit_suffix"));
}
get name(): string {

View file

@ -1,9 +1,8 @@
import { Page } from "../../types/Page";
import { changePage, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { getSecretMetadata } from "../../api/kv/getSecretMetadata";
import { makeElement } from "../../htmlUtils";
import { objectToMap } from "../../utils";
import { pageState } from "../../globalPageState";
import i18next from "i18next";
export class KeyValueVersionsPage extends Page {
@ -11,25 +10,23 @@ export class KeyValueVersionsPage extends Page {
super();
}
async goBack(): Promise<void> {
if (pageState.currentSecretVersion != null) {
pageState.currentSecretVersion = null;
if (this.state.currentSecretVersion != null) {
this.state.currentSecretVersion = null;
}
await changePage("KEY_VALUE_SECRET");
await this.router.changePage("KEY_VALUE_SECRET");
}
async render(): Promise<void> {
setTitleElement(pageState);
const versionsList = makeElement({
tag: "ul",
id: "versionsList",
class: ["uk-nav", "uk-nav-default"],
});
setPageContent(versionsList);
await this.router.setPageContent(versionsList);
const metadata = await getSecretMetadata(
pageState.currentBaseMount,
pageState.currentSecretPath,
pageState.currentSecret,
this.state.currentBaseMount,
this.state.currentSecretPath,
this.state.currentSecret,
);
objectToMap(metadata.versions).forEach((_, ver) => {
@ -40,8 +37,8 @@ export class KeyValueVersionsPage extends Page {
tag: "a",
text: `v${ver}`,
onclick: async () => {
pageState.currentSecretVersion = ver;
await changePage("KEY_VALUE_SECRET");
this.state.currentSecretVersion = ver;
await this.router.changePage("KEY_VALUE_SECRET");
},
}),
}),
@ -49,8 +46,8 @@ export class KeyValueVersionsPage extends Page {
});
}
get titleSuffix(): string {
return i18next.t("kv_sec_versions_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("kv_sec_versions_suffix"));
}
get name(): string {

View file

@ -1,9 +1,9 @@
import { DoesNotExistError } from "../../types/internalErrors";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { getSecrets } from "../../api/kv/getSecrets";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
export class KeyValueViewPage extends Page {
@ -11,22 +11,20 @@ export class KeyValueViewPage extends Page {
super();
}
async goBack(): Promise<void> {
if (pageState.currentSecretPath.length != 0) {
pageState.popCurrentSecretPath();
await changePage("KEY_VALUE_VIEW");
if (this.state.currentSecretPath.length != 0) {
this.state.popCurrentSecretPath();
await this.router.changePage("KEY_VALUE_VIEW");
} else {
await changePage("HOME");
await this.router.changePage("HOME");
}
}
async render(): Promise<void> {
pageState.currentSecret = "";
setTitleElement(pageState);
this.state.currentSecret = "";
const kvViewPageContent = makeElement({ tag: "div" });
setPageContent(kvViewPageContent);
await this.router.setPageContent(kvViewPageContent);
if (pageState.currentMountType == "cubbyhole") {
if (this.state.currentMountType == "cubbyhole") {
kvViewPageContent.appendChild(
makeElement({
tag: "p",
@ -40,16 +38,16 @@ export class KeyValueViewPage extends Page {
text: i18next.t("kv_view_new_btn"),
class: ["uk-button", "uk-button-primary", "uk-margin-bottom"],
onclick: async () => {
await changePage("KEY_VALUE_NEW_SECRET");
await this.router.changePage("KEY_VALUE_NEW_SECRET");
},
});
kvViewPageContent.appendChild(newButton);
try {
const res = await getSecrets(
pageState.currentBaseMount,
pageState.currentMountType,
pageState.currentSecretPath,
this.state.currentBaseMount,
this.state.currentMountType,
this.state.currentSecretPath,
);
kvViewPageContent.appendChild(
@ -57,7 +55,7 @@ export class KeyValueViewPage extends Page {
tag: "ul",
class: ["uk-nav", "uk-nav-default"],
children: [
...res.map(function (secret) {
...res.map((secret) => {
return makeElement({
tag: "li",
children: makeElement({
@ -65,11 +63,11 @@ export class KeyValueViewPage extends Page {
text: secret,
onclick: async () => {
if (secret.endsWith("/")) {
pageState.pushCurrentSecretPath(secret);
await changePage("KEY_VALUE_VIEW");
this.state.pushCurrentSecretPath(secret);
await this.router.changePage("KEY_VALUE_VIEW");
} else {
pageState.currentSecret = secret;
await changePage("KEY_VALUE_SECRET");
this.state.currentSecret = secret;
await this.router.changePage("KEY_VALUE_SECRET");
}
},
}),
@ -82,7 +80,7 @@ export class KeyValueViewPage extends Page {
const error = e as Error;
if (error == DoesNotExistError) {
// getSecrets also 404's on no keys so dont go all the way back.
if (pageState.currentSecretPath.length != 0) {
if (this.state.currentSecretPath.length != 0) {
return this.goBack();
} else {
kvViewPageContent.appendChild(
@ -98,6 +96,10 @@ export class KeyValueViewPage extends Page {
}
}
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router);
}
get name(): string {
return i18next.t("kv_view_title");
}

View file

@ -1,10 +1,9 @@
import { Margin } from "../elements/Margin";
import { MarginInline } from "../elements/MarginInline";
import { Page } from "../types/Page";
import { changePage, setErrorText, setPageContent } from "../pageUtils";
import { Page } from "../PageSystem/Page";
import { lookupSelf } from "../api/sys/lookupSelf";
import { makeElement } from "../htmlUtils";
import { pageState } from "../globalPageState";
import { setErrorText } from "../pageUtils";
import { usernameLogin } from "../api/auth/usernameLogin";
import i18next from "i18next";
@ -83,7 +82,7 @@ export class LoginPage extends Page {
],
}) as HTMLFormElement;
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
children: [
@ -132,15 +131,15 @@ export class LoginPage extends Page {
}),
);
tokenLoginForm.addEventListener("submit", async function (e) {
tokenLoginForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(tokenLoginForm);
const token = formData.get("token");
pageState.token = token as string;
this.state.token = token as string;
try {
await lookupSelf();
await changePage("HOME");
await this.router.changePage("HOME");
} catch (e: unknown) {
const error = e as Error;
document.getElementById("tokenInput").classList.add("uk-form-danger");
@ -151,7 +150,7 @@ export class LoginPage extends Page {
}
}
});
usernameLoginForm.addEventListener("submit", async function (e) {
usernameLoginForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(usernameLoginForm);
@ -160,8 +159,8 @@ export class LoginPage extends Page {
formData.get("username") as string,
formData.get("password") as string,
);
pageState.token = res;
await changePage("HOME");
this.state.token = res;
await this.router.changePage("HOME");
} catch (e: unknown) {
const error = e as Error;
document.getElementById("usernameInput").classList.add("uk-form-danger");

View file

@ -1,14 +1,7 @@
import { Page } from "../types/Page";
import {
addClipboardNotifications,
changePage,
prePageChecks,
setErrorText,
setPageContent,
} from "../pageUtils";
import { Page } from "../PageSystem/Page";
import { addClipboardNotifications, prePageChecks, setErrorText } from "../pageUtils";
import { getCapabilitiesPath } from "../api/sys/getCapabilities";
import { makeElement } from "../htmlUtils";
import { pageState } from "../globalPageState";
import { renewSelf } from "../api/sys/renewSelf";
import { sealVault } from "../api/sys/sealVault";
import ClipboardJS from "clipboard";
@ -20,8 +13,8 @@ export class MePage extends Page {
}
async render(): Promise<void> {
if (!(await prePageChecks())) return;
setPageContent(
if (!(await prePageChecks(this.router))) return;
await this.router.setPageContent(
makeElement({
tag: "ul",
class: "uk-nav",
@ -32,8 +25,8 @@ export class MePage extends Page {
tag: "a",
text: i18next.t("log_out_btn"),
onclick: async () => {
pageState.token = "";
await changePage("HOME");
this.state.token = "";
await this.router.changePage("HOME");
},
}),
}),
@ -43,7 +36,7 @@ export class MePage extends Page {
tag: "a",
text: i18next.t("copy_token_btn"),
attributes: {
"data-clipboard-text": pageState.token,
"data-clipboard-text": this.state.token,
},
thenRun: (e) => {
const clipboard = new ClipboardJS(e);
@ -59,7 +52,7 @@ export class MePage extends Page {
onclick: () => {
renewSelf()
.then(() => {
void changePage("HOME");
void this.router.changePage("HOME");
})
.catch((e: Error) => {
setErrorText(e.message);
@ -82,7 +75,7 @@ export class MePage extends Page {
text: i18next.t("seal_vault_btn"),
onclick: async () => {
await sealVault();
await changePage("UNSEAL_VAULT");
await this.router.changePage("UNSEAL_VAULT");
},
}),
}),
@ -92,7 +85,7 @@ export class MePage extends Page {
tag: "a",
text: i18next.t("change_language_btn"),
onclick: async () => {
await changePage("SET_LANGUAGE");
await this.router.changePage("SET_LANGUAGE");
},
}),
}),

View file

@ -1,10 +1,9 @@
import { Margin } from "../../elements/Margin";
import { Option } from "../../elements/Option";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { makeElement } from "../../htmlUtils";
import { newMount } from "../../api/sys/newMount";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
export class NewKVEnginePage extends Page {
@ -56,9 +55,9 @@ export class NewKVEnginePage extends Page {
],
}) as HTMLFormElement;
setPageContent(newEngineForm);
await this.router.setPageContent(newEngineForm);
newEngineForm.addEventListener("submit", async function (e) {
newEngineForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(newEngineForm);
@ -73,9 +72,9 @@ export class NewKVEnginePage extends Page {
version: version,
},
});
pageState.currentMountType = "kv-v" + version;
pageState.currentBaseMount = name + "/";
await changePage("KEY_VALUE_VIEW");
this.state.currentMountType = "kv-v" + version;
this.state.currentBaseMount = name + "/";
await this.router.changePage("KEY_VALUE_VIEW");
} catch (e) {
const error = e as Error;
setErrorText(error.message);

View file

@ -1,9 +1,8 @@
import { Margin } from "../../elements/Margin";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { makeElement } from "../../htmlUtils";
import { newMount } from "../../api/sys/newMount";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
export class NewTOTPEnginePage extends Page {
@ -42,9 +41,9 @@ export class NewTOTPEnginePage extends Page {
],
}) as HTMLFormElement;
setPageContent(newEngineForm);
await this.router.setPageContent(newEngineForm);
newEngineForm.addEventListener("submit", async function (e) {
newEngineForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(newEngineForm);
@ -55,9 +54,9 @@ export class NewTOTPEnginePage extends Page {
name: name,
type: "totp",
});
pageState.currentMountType = "totp";
pageState.currentBaseMount = name + "/";
await changePage("TOTP");
this.state.currentMountType = "totp";
this.state.currentBaseMount = name + "/";
await this.router.changePage("TOTP");
} catch (e) {
const error = e as Error;
setErrorText(error.message);

View file

@ -1,9 +1,8 @@
import { Margin } from "../../elements/Margin";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { makeElement } from "../../htmlUtils";
import { newMount } from "../../api/sys/newMount";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
export class NewTransitEnginePage extends Page {
@ -42,9 +41,9 @@ export class NewTransitEnginePage extends Page {
],
}) as HTMLFormElement;
setPageContent(newEngineForm);
await this.router.setPageContent(newEngineForm);
newEngineForm.addEventListener("submit", async function (e) {
newEngineForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(newEngineForm);
@ -55,9 +54,9 @@ export class NewTransitEnginePage extends Page {
name: name,
type: "transit",
});
pageState.currentMountType = "transit";
pageState.currentBaseMount = name + "/";
await changePage("TRANSIT_VIEW");
this.state.currentMountType = "transit";
this.state.currentBaseMount = name + "/";
await this.router.changePage("TRANSIT_VIEW");
} catch (e) {
const error = e as Error;
setErrorText(error.message);

View file

@ -1,6 +1,5 @@
import { Page } from "../types/Page";
import { Page } from "../PageSystem/Page";
import { Tile } from "../elements/Tile";
import { changePage, setPageContent } from "../pageUtils";
import { makeElement } from "../htmlUtils";
import i18next from "i18next";
@ -10,7 +9,7 @@ export class NewSecretsEnginePage extends Page {
}
async render(): Promise<void> {
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
class: "uk-child-width-1-1@s uk-child-width-1-2@m uk-grid-small uk-grid-match",
@ -19,22 +18,22 @@ export class NewSecretsEnginePage extends Page {
Tile({
title: i18next.t("new_secrets_engine_kv_title"),
description: i18next.t("new_secrets_engine_kv_description"),
onclick: () => {
void changePage("NEW_KV_ENGINE");
onclick: async () => {
await this.router.changePage("NEW_KV_ENGINE");
},
}),
Tile({
title: i18next.t("new_secrets_engine_totp_title"),
description: i18next.t("new_secrets_engine_totp_description"),
onclick: () => {
void changePage("NEW_TOTP_ENGINE");
onclick: async () => {
await this.router.changePage("NEW_TOTP_ENGINE");
},
}),
Tile({
title: i18next.t("new_secrets_engine_transit_title"),
description: i18next.t("new_secrets_engine_transit_description"),
onclick: () => {
void changePage("NEW_TRANSIT_ENGINE");
onclick: async () => {
await this.router.changePage("NEW_TRANSIT_ENGINE");
},
}),
],

View file

@ -1,9 +1,8 @@
import { CopyableInputBox, CopyableInputBoxType } from "../elements/CopyableInputBox";
import { Margin } from "../elements/Margin";
import { Option } from "../elements/Option";
import { Page } from "../types/Page";
import { Page } from "../PageSystem/Page";
import { makeElement } from "../htmlUtils";
import { setPageContent } from "../pageUtils";
import i18next from "i18next";
const passwordLengthMin = 1;
@ -59,7 +58,7 @@ export class PwGenPage extends Page {
passwordForm: HTMLFormElement;
async render(): Promise<void> {
setPageContent("");
await this.router.setPageContent("");
this.passwordBox = CopyableInputBox(genPassword(passwordOptionsDefault));
this.passwordLengthTitle = makeElement({
@ -110,7 +109,7 @@ export class PwGenPage extends Page {
}) as HTMLFormElement;
this.passwordForm.addEventListener("submit", (e) => this.formEvent(e));
setPageContent(this.passwordForm);
await this.router.setPageContent(this.passwordForm);
}
getPasswordLengthText(): string {

View file

@ -1,8 +1,6 @@
import { Margin } from "../elements/Margin";
import { Page } from "../types/Page";
import { changePage, setPageContent } from "../pageUtils";
import { Page } from "../PageSystem/Page";
import { makeElement } from "../htmlUtils";
import { pageState } from "../globalPageState";
import { reloadNavBar } from "../elements/NavBar";
import i18next from "i18next";
@ -51,18 +49,18 @@ export class SetLanguagePage extends Page {
}),
],
}) as HTMLFormElement;
setPageContent(setLanguageForm);
setLanguageForm.addEventListener("submit", async function (e) {
await this.router.setPageContent(setLanguageForm);
setLanguageForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(setLanguageForm);
const language = formData.get("language") as string;
pageState.language = language;
this.state.language = language;
const t = await i18next.changeLanguage(language);
pageState.pageDirection = t("language_direction");
reloadNavBar();
await changePage("HOME");
this.state.pageDirection = t("language_direction");
reloadNavBar(this.router);
await this.router.changePage("HOME");
});
}
get name(): string {

View file

@ -1,14 +1,12 @@
import { Page } from "../types/Page";
import { changePage, setPageContent } from "../pageUtils";
import { Page } from "../PageSystem/Page";
import { makeElement } from "../htmlUtils";
import { pageState } from "../globalPageState";
export class SetVaultURLPage extends Page {
constructor() {
super();
}
async render(): Promise<void> {
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "form",
id: "setVaultURLForm",
@ -43,11 +41,11 @@ export class SetVaultURLPage extends Page {
],
}),
);
document.getElementById("setVaultURLForm").addEventListener("submit", async function (e) {
document.getElementById("setVaultURLForm").addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(document.querySelector("#setVaultURLForm"));
pageState.apiURL = formData.get("vaultURL") as string;
await changePage("HOME");
this.state.apiURL = formData.get("vaultURL") as string;
await this.router.changePage("HOME");
});
}
get name(): string {

View file

@ -1,10 +1,10 @@
import { Margin } from "../../elements/Margin";
import { MarginInline } from "../../elements/MarginInline";
import { Page } from "../../types/Page";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { addNewTOTP } from "../../api/totp/addNewTOTP";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
function replaceAll(str: string, replace: string, replaceWith: string): string {
@ -21,11 +21,9 @@ export class NewTOTPPage extends Page {
super();
}
async goBack(): Promise<void> {
await changePage("TOTP");
await this.router.changePage("TOTP");
}
async render(): Promise<void> {
setTitleElement(pageState);
const totpForm = makeElement({
tag: "form",
children: [
@ -84,9 +82,9 @@ export class NewTOTPPage extends Page {
),
],
}) as HTMLFormElement;
setPageContent(totpForm);
await this.router.setPageContent(totpForm);
totpForm.addEventListener("submit", async function (e) {
totpForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(totpForm);
@ -99,8 +97,8 @@ export class NewTOTPPage extends Page {
};
try {
await addNewTOTP(pageState.currentBaseMount, parms);
await changePage("TOTP");
await addNewTOTP(this.state.currentBaseMount, parms);
await this.router.changePage("TOTP");
} catch (e: unknown) {
const error = e as Error;
setErrorText(`API Error: ${error.message}`);
@ -108,8 +106,8 @@ export class NewTOTPPage extends Page {
});
}
get titleSuffix(): string {
return i18next.t("totp_new_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("totp_new_suffix"));
}
get name(): string {

View file

@ -1,12 +1,12 @@
import { CopyableInputBox } from "../../elements/CopyableInputBox";
import { DoesNotExistError } from "../../types/internalErrors";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { getTOTPCode } from "../../api/totp/getTOTPCode";
import { getTOTPKeys } from "../../api/totp/getTOTPKeys";
import { makeElement } from "../../htmlUtils";
import { objectToMap } from "../../utils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
export interface TOTPListElement extends HTMLElement {
@ -24,9 +24,8 @@ export class TOTPViewPage extends Page {
totpListElements: Record<string, TOTPListElement>;
async render(): Promise<void> {
setTitleElement(pageState);
const totpList = makeElement({ tag: "div" });
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
children: [
@ -35,7 +34,7 @@ export class TOTPViewPage extends Page {
text: i18next.t("totp_view_new_btn"),
class: ["uk-button", "uk-button-primary", "uk-margin-bottom"],
onclick: async () => {
await changePage("NEW_TOTP");
await this.router.changePage("NEW_TOTP");
},
}),
makeElement({
@ -51,7 +50,7 @@ export class TOTPViewPage extends Page {
);
try {
const res = await getTOTPKeys(pageState.currentBaseMount);
const res = await getTOTPKeys(this.state.currentBaseMount);
for (const totpKeyName of res) {
const totpListElement = this.makeTOTPListElement(totpKeyName);
totpList.appendChild(totpListElement);
@ -88,7 +87,7 @@ export class TOTPViewPage extends Page {
}
async updateTOTPElement(totpKeyName: string, totpListElement: TOTPListElement): Promise<void> {
totpListElement.setCode(await getTOTPCode(pageState.currentBaseMount, totpKeyName));
totpListElement.setCode(await getTOTPCode(this.state.currentBaseMount, totpKeyName));
}
makeTOTPListElement(totpKeyName: string): TOTPListElement {
@ -106,6 +105,10 @@ export class TOTPViewPage extends Page {
return gridElement;
}
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router);
}
get name(): string {
return i18next.t("totp_view_title");
}

View file

@ -1,10 +1,10 @@
import { Margin } from "../../elements/Margin";
import { Option } from "../../elements/Option";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { makeElement } from "../../htmlUtils";
import { newTransitKey } from "../../api/transit/newTransitKey";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
export class NewTransitKeyPage extends Page {
@ -12,8 +12,6 @@ export class NewTransitKeyPage extends Page {
super();
}
async render(): Promise<void> {
setTitleElement(pageState);
const newTransitKeyForm = makeElement({
tag: "form",
children: [
@ -66,9 +64,9 @@ export class NewTransitKeyPage extends Page {
],
}) as HTMLFormElement;
setPageContent(newTransitKeyForm);
await this.router.setPageContent(newTransitKeyForm);
newTransitKeyForm.addEventListener("submit", async function (e) {
newTransitKeyForm.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(newTransitKeyForm);
@ -76,12 +74,12 @@ export class NewTransitKeyPage extends Page {
const type = formData.get("type") as string;
try {
await newTransitKey(pageState.currentBaseMount, {
await newTransitKey(this.state.currentBaseMount, {
name: name,
type: type,
});
pageState.currentSecret = name;
await changePage("TRANSIT_VIEW_SECRET");
this.state.currentSecret = name;
await this.router.changePage("TRANSIT_VIEW_SECRET");
} catch (e) {
const error = e as Error;
setErrorText(error.message);
@ -89,8 +87,8 @@ export class NewTransitKeyPage extends Page {
});
}
get titleSuffix(): string {
return i18next.t("transit_new_key_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("transit_new_key_suffix"));
}
get name(): string {

View file

@ -1,10 +1,10 @@
import { CopyableModal } from "../../elements/CopyableModal";
import { FileUploadInput } from "../../elements/FileUploadInput";
import { Margin } from "../../elements/Margin";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { fileToBase64, makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import { transitDecrypt } from "../../api/transit/transitDecrypt";
import i18next from "i18next";
@ -14,14 +14,13 @@ export class TransitDecryptPage extends Page {
}
async goBack(): Promise<void> {
await changePage("TRANSIT_VIEW_SECRET");
await this.router.changePage("TRANSIT_VIEW_SECRET");
}
transitDecryptForm: HTMLFormElement;
async render(): Promise<void> {
setTitleElement(pageState);
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
}),
@ -74,7 +73,7 @@ export class TransitDecryptPage extends Page {
}),
],
}) as HTMLFormElement;
setPageContent(this.transitDecryptForm);
await this.router.setPageContent(this.transitDecryptForm);
this.transitDecryptForm.addEventListener("submit", async (e: Event) => {
e.preventDefault();
await this.transitDecryptFormHandler();
@ -96,7 +95,7 @@ export class TransitDecryptPage extends Page {
}
try {
const res = await transitDecrypt(pageState.currentBaseMount, pageState.currentSecret, {
const res = await transitDecrypt(this.state.currentBaseMount, this.state.currentSecret, {
ciphertext: ciphertext,
});
let plaintext = res.plaintext;
@ -115,8 +114,8 @@ export class TransitDecryptPage extends Page {
}
}
get titleSuffix(): string {
return i18next.t("transit_decrypt_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("transit_decrypt_suffix"));
}
get name(): string {

View file

@ -1,10 +1,10 @@
import { CopyableModal } from "../../elements/CopyableModal";
import { FileUploadInput } from "../../elements/FileUploadInput";
import { Margin } from "../../elements/Margin";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { fileToBase64, makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import { transitEncrypt } from "../../api/transit/transitEncrypt";
import i18next from "i18next";
@ -14,14 +14,13 @@ export class TransitEncryptPage extends Page {
}
async goBack(): Promise<void> {
await changePage("TRANSIT_VIEW_SECRET");
await this.router.changePage("TRANSIT_VIEW_SECRET");
}
transitEncryptForm: HTMLFormElement;
async render(): Promise<void> {
setTitleElement(pageState);
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
}),
@ -74,7 +73,7 @@ export class TransitEncryptPage extends Page {
}),
],
}) as HTMLFormElement;
setPageContent(this.transitEncryptForm);
await this.router.setPageContent(this.transitEncryptForm);
this.transitEncryptForm.addEventListener("submit", async (e: Event) => {
e.preventDefault();
@ -98,7 +97,7 @@ export class TransitEncryptPage extends Page {
}
try {
const res = await transitEncrypt(pageState.currentBaseMount, pageState.currentSecret, {
const res = await transitEncrypt(this.state.currentBaseMount, this.state.currentSecret, {
plaintext: plaintext,
});
const modal = CopyableModal(
@ -113,8 +112,8 @@ export class TransitEncryptPage extends Page {
}
}
get titleSuffix(): string {
return i18next.t("transit_encrypt_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("transit_encrypt_suffix"));
}
get name(): string {

View file

@ -1,12 +1,12 @@
import { CopyableModal } from "../../elements/CopyableModal";
import { Margin } from "../../elements/Margin";
import { Option } from "../../elements/Option";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { getTransitKey } from "../../api/transit/getTransitKey";
import { makeElement } from "../../htmlUtils";
import { objectToMap } from "../../utils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import { transitRewrap } from "../../api/transit/transitRewrap";
import i18next from "i18next";
@ -18,14 +18,13 @@ export class TransitRewrapPage extends Page {
}
async goBack(): Promise<void> {
await changePage("TRANSIT_VIEW_SECRET");
await this.router.changePage("TRANSIT_VIEW_SECRET");
}
transitRewrapForm: HTMLFormElement;
async render(): Promise<void> {
setTitleElement(pageState);
const transitKey = await getTransitKey(pageState.currentBaseMount, pageState.currentSecret);
const transitKey = await getTransitKey(this.state.currentBaseMount, this.state.currentSecret);
const stringVersions = Array.from(
objectToMap(transitKey.keys).keys(),
@ -47,7 +46,7 @@ export class TransitRewrapPage extends Page {
};
});
setPageContent("");
await this.router.setPageContent("");
this.transitRewrapForm = makeElement({
tag: "form",
children: [
@ -82,7 +81,7 @@ export class TransitRewrapPage extends Page {
}),
],
}) as HTMLFormElement;
setPageContent(this.transitRewrapForm);
await this.router.setPageContent(this.transitRewrapForm);
this.transitRewrapForm.addEventListener("submit", async (e: Event) => {
e.preventDefault();
@ -93,7 +92,7 @@ export class TransitRewrapPage extends Page {
async transitRewrapFormHandler(): Promise<void> {
const formData = new FormData(this.transitRewrapForm);
try {
const res = await transitRewrap(pageState.currentBaseMount, pageState.currentSecret, {
const res = await transitRewrap(this.state.currentBaseMount, this.state.currentSecret, {
ciphertext: formData.get("ciphertext") as string,
key_version: parseInt(formData.get("version") as string, 10),
});
@ -106,8 +105,8 @@ export class TransitRewrapPage extends Page {
}
}
get titleSuffix(): string {
return i18next.t("transit_rewrap_suffix");
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router, i18next.t("transit_rewrap_suffix"));
}
get name(): string {

View file

@ -1,9 +1,9 @@
import { DoesNotExistError } from "../../types/internalErrors";
import { Page } from "../../types/Page";
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { getTransitKeys } from "../../api/transit/getTransitKeys";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import { setErrorText } from "../../pageUtils";
import i18next from "i18next";
export class TransitViewPage extends Page {
@ -12,44 +12,42 @@ export class TransitViewPage extends Page {
}
async goBack(): Promise<void> {
await changePage("HOME");
await this.router.changePage("HOME");
}
async render(): Promise<void> {
pageState.currentSecret = "";
setTitleElement(pageState);
this.state.currentSecret = "";
const transitViewContent = makeElement({ tag: "div" });
setPageContent(transitViewContent);
await this.router.setPageContent(transitViewContent);
const newButton = makeElement({
tag: "button",
text: "New",
class: ["uk-button", "uk-button-primary", "uk-margin-bottom"],
onclick: () => {
void changePage("TRANSIT_NEW_KEY");
onclick: async () => {
await this.router.changePage("TRANSIT_NEW_KEY");
},
});
transitViewContent.appendChild(newButton);
try {
const res = await getTransitKeys(pageState.currentBaseMount);
const res = await getTransitKeys(this.state.currentBaseMount);
transitViewContent.appendChild(
makeElement({
tag: "ul",
class: ["uk-nav", "uk-nav-default"],
children: [
...res.map(function (secret) {
...res.map((secret) => {
return makeElement({
tag: "li",
children: makeElement({
tag: "a",
text: secret,
onclick: () => {
pageState.currentSecret = secret;
void changePage("TRANSIT_VIEW_SECRET");
onclick: async () => {
this.state.currentSecret = secret;
await this.router.changePage("TRANSIT_VIEW_SECRET");
},
}),
});
@ -72,6 +70,10 @@ export class TransitViewPage extends Page {
}
}
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router);
}
get name(): string {
return i18next.t("transit_view_title");
}

View file

@ -1,9 +1,8 @@
import { Page } from "../../types/Page";
import { Page } from "../../PageSystem/Page";
import { SecretTitleElement } from "../../elements/SecretTitleElement";
import { Tile } from "../../elements/Tile";
import { changePage, setPageContent, setTitleElement } from "../../pageUtils";
import { getTransitKey } from "../../api/transit/getTransitKey";
import { makeElement } from "../../htmlUtils";
import { pageState } from "../../globalPageState";
import i18next from "i18next";
export class TransitViewSecretPage extends Page {
@ -12,15 +11,13 @@ export class TransitViewSecretPage extends Page {
}
async goBack(): Promise<void> {
await changePage("TRANSIT_VIEW");
await this.router.changePage("TRANSIT_VIEW");
}
async render(): Promise<void> {
setTitleElement(pageState);
const transitKey = await getTransitKey(this.state.currentBaseMount, this.state.currentSecret);
const transitKey = await getTransitKey(pageState.currentBaseMount, pageState.currentSecret);
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
class: "uk-child-width-1-1@s uk-child-width-1-2@m uk-grid-small uk-grid-match",
@ -32,8 +29,8 @@ export class TransitViewSecretPage extends Page {
description: i18next.t("transit_view_encrypt_description"),
icon: "lock",
iconText: i18next.t("transit_view_encrypt_icon_text"),
onclick: () => {
void changePage("TRANSIT_ENCRYPT");
onclick: async () => {
await this.router.changePage("TRANSIT_ENCRYPT");
},
}),
Tile({
@ -42,8 +39,8 @@ export class TransitViewSecretPage extends Page {
description: i18next.t("transit_view_decrypt_description"),
icon: "mail",
iconText: i18next.t("transit_view_decrypt_icon_text"),
onclick: () => {
void changePage("TRANSIT_DECRYPT");
onclick: async () => {
await this.router.changePage("TRANSIT_DECRYPT");
},
}),
Tile({
@ -52,8 +49,8 @@ export class TransitViewSecretPage extends Page {
description: i18next.t("transit_view_rewrap_description"),
icon: "code",
iconText: i18next.t("transit_view_rewrap_icon_text"),
onclick: () => {
void changePage("TRANSIT_REWRAP");
onclick: async () => {
await this.router.changePage("TRANSIT_REWRAP");
},
}),
],
@ -61,6 +58,10 @@ export class TransitViewSecretPage extends Page {
);
}
async getPageTitle(): Promise<Element | string> {
return await SecretTitleElement(this.router);
}
get name(): string {
return i18next.t("transit_view_secret_title");
}

View file

@ -1,9 +1,9 @@
import { MarginInline } from "../elements/MarginInline";
import { Page } from "../types/Page";
import { Page } from "../PageSystem/Page";
import { QRScanner, QRScannerType } from "../elements/QRScanner";
import { SealStatusType, getSealStatus } from "../api/sys/getSealStatus";
import { changePage, setErrorText, setPageContent } from "../pageUtils";
import { makeElement } from "../htmlUtils";
import { setErrorText } from "../pageUtils";
import { submitUnsealKey } from "../api/sys/submitUnsealKey";
import i18next from "i18next";
@ -68,7 +68,7 @@ export class UnsealPage extends Page {
this.unsealInputContent = makeElement({
tag: "div",
});
setPageContent(
await this.router.setPageContent(
makeElement({
tag: "div",
children: [
@ -169,7 +169,7 @@ export class UnsealPage extends Page {
progressBar.max = keysNeeded;
if (!data.sealed) {
progressBar.value = keysNeeded;
await changePage("HOME");
await this.router.changePage("HOME");
}
}

View file

@ -1,7 +1,5 @@
import { PageRouter } from "./PageRouter";
import { PageRouter } from "./PageSystem/PageRouter";
import { PageState } from "./PageState";
import { pageRouter } from "./globalPageRouter";
import { pageState } from "./globalPageState";
import i18next from "i18next";
// Playground is a way to debug and test things.
@ -18,9 +16,9 @@ declare global {
}
// Please empty this function before committing.
export async function playground(): Promise<void> {
export async function playground(router: PageRouter): Promise<void> {
console.log("Welcome to Playground!");
window.pageState = pageState;
window.pageState = router.state;
window.i18next = i18next;
window.router = pageRouter;
window.router = router;
}

View file

@ -1,20 +0,0 @@
import { changePage } from "../pageUtils";
export class Page {
constructor() {
// Do Nothing
}
async render(): Promise<void> {}
get name(): string {
return "Page";
}
get titleSuffix(): string {
return "";
}
async goBack(): Promise<void> {
await changePage("HOME");
}
async cleanup(): Promise<void> {
// Do Nothing
}
}