initial work on moving to a real page router
This commit is contained in:
parent
da163c931a
commit
c62cd89771
|
@ -17,6 +17,7 @@
|
|||
"codejar": "^3.5.0",
|
||||
"core-js": "^3.20.2",
|
||||
"css-loader": "^6.5.1",
|
||||
"css-minimizer-webpack-plugin": "^3.3.1",
|
||||
"date-fns": "^2.28.0",
|
||||
"eslint": "^8.6.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
|
@ -41,7 +42,9 @@
|
|||
"uikit": "^3.9.4",
|
||||
"webpack": "^5.65.0",
|
||||
"webpack-cli": "^4.9.1",
|
||||
"webpack-dev-server": "^4.7.2",
|
||||
"css-minimizer-webpack-plugin": "^3.3.1"
|
||||
"webpack-dev-server": "^4.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact-router": "^4.0.0"
|
||||
}
|
||||
}
|
||||
|
|
242
src/allPages.ts
242
src/allPages.ts
|
@ -1,121 +1,121 @@
|
|||
import { PageType } from "./pagerouter/PageType";
|
||||
|
||||
import { AccessHomePage } from "./ui/pages/Access/AccessHome";
|
||||
import { AuthHomePage } from "./ui/pages/Access/Auth/AuthHome";
|
||||
import { AuthViewConfigPage } from "./ui/pages/Access/Auth/AuthViewConfig";
|
||||
import { DeleteSecretsEnginePage } from "./ui/pages/Secrets/DeleteSecretsEngine";
|
||||
import { HomePage } from "./ui/pages/Home";
|
||||
import { KeyValueDeletePage } from "./ui/pages/Secrets/KeyValue/KeyValueDelete";
|
||||
import { KeyValueNewPage } from "./ui/pages/Secrets/KeyValue/KeyValueNew";
|
||||
import { KeyValueSecretEditPage } from "./ui/pages/Secrets/KeyValue/KeyValueSecretsEdit";
|
||||
import { KeyValueSecretPage } from "./ui/pages/Secrets/KeyValue/KeyValueSecret";
|
||||
import { KeyValueVersionsPage } from "./ui/pages/Secrets/KeyValue/KeyValueVersions";
|
||||
import { KeyValueViewPage } from "./ui/pages/Secrets/KeyValue/KeyValueView";
|
||||
import { LoginPage } from "./ui/pages/Login";
|
||||
import { MePage } from "./ui/pages/Me";
|
||||
import { NewKVEnginePage } from "./ui/pages/Secrets/NewEngines/NewKVEngine";
|
||||
import { NewSecretsEnginePage } from "./ui/pages/Secrets/NewSecretsEngine";
|
||||
import { NewTOTPEnginePage } from "./ui/pages/Secrets/NewEngines/NewTOTPEngine";
|
||||
import { NewTransitEnginePage } from "./ui/pages/Secrets/NewEngines/NewTransitEngine";
|
||||
import { NewTransitKeyPage } from "./ui/pages/Secrets/Transit/NewTransitKey";
|
||||
import { Page } from "./types/Page";
|
||||
import { PoliciesHomePage } from "./ui/pages/Policies/PoliciesHome";
|
||||
import { PolicyDeletePage } from "./ui/pages/Policies/PolicyDelete";
|
||||
import { PolicyEditPage } from "./ui/pages/Policies/PolicyEdit";
|
||||
import { PolicyNewPage } from "./ui/pages/Policies/PolicyNew";
|
||||
import { PolicyViewPage } from "./ui/pages/Policies/PolicyView";
|
||||
import { PwGenPage } from "./ui/pages/PwGen";
|
||||
import { SecretsHomePage } from "./ui/pages/Secrets/SecretsHome";
|
||||
import { SetLanguagePage } from "./ui/pages/SetLanguage";
|
||||
import { SetVaultURLPage } from "./ui/pages/SetVaultURL";
|
||||
import { TOTPDeletePage } from "./ui/pages/Secrets/TOTP/TOTPDelete";
|
||||
import { TOTPNewPage } from "./ui/pages/Secrets/TOTP/TOTPNew";
|
||||
import { TOTPViewPage } from "./ui/pages/Secrets/TOTP/TOTPView";
|
||||
import { TransitDecryptPage } from "./ui/pages/Secrets/Transit/TransitDecrypt";
|
||||
import { TransitEncryptPage } from "./ui/pages/Secrets/Transit/TransitEncrypt";
|
||||
import { TransitRewrapPage } from "./ui/pages/Secrets/Transit/TransitRewrap";
|
||||
import { TransitViewPage } from "./ui/pages/Secrets/Transit/TransitView";
|
||||
import { TransitViewSecretPage } from "./ui/pages/Secrets/Transit/TransitViewSecret";
|
||||
import { UnsealPage } from "./ui/pages/Unseal";
|
||||
import { UserPassUserDeletePage } from "./ui/pages/Access/Auth/userpass/UserPassUserDelete";
|
||||
import { UserPassUserEditPage } from "./ui/pages/Access/Auth/userpass/UserPassUserEdit";
|
||||
import { UserPassUserNewPage } from "./ui/pages/Access/Auth/userpass/UserPassUserNew";
|
||||
import { UserPassUserViewPage } from "./ui/pages/Access/Auth/userpass/UserPassUserView";
|
||||
import { UserPassUsersListPage } from "./ui/pages/Access/Auth/userpass/UserPassUsersList";
|
||||
import { getObjectKeys } from "./utils";
|
||||
|
||||
type pagesList = {
|
||||
[key: string]: Page;
|
||||
};
|
||||
|
||||
export const allPages: pagesList = {
|
||||
HOME: new HomePage(),
|
||||
LOGIN: new LoginPage(),
|
||||
SET_VAULT_URL: new SetVaultURLPage(),
|
||||
UNSEAL: new UnsealPage(),
|
||||
SET_LANGUAGE: new SetLanguagePage(),
|
||||
ME: new MePage(),
|
||||
PW_GEN: new PwGenPage(),
|
||||
|
||||
POLICIES_HOME: new PoliciesHomePage(),
|
||||
POLICY_VIEW: new PolicyViewPage(),
|
||||
POLICY_NEW: new PolicyNewPage(),
|
||||
POLICY_EDIT: new PolicyEditPage(),
|
||||
POLICY_DELETE: new PolicyDeletePage(),
|
||||
|
||||
ACCESS_HOME: new AccessHomePage(),
|
||||
|
||||
AUTH_HOME: new AuthHomePage(),
|
||||
AUTH_VIEW_CONFIG: new AuthViewConfigPage(),
|
||||
|
||||
USERPASS_USERS_LIST: new UserPassUsersListPage(),
|
||||
USERPASS_USER_VIEW: new UserPassUserViewPage(),
|
||||
USERPASS_USER_EDIT: new UserPassUserEditPage(),
|
||||
USERPASS_USER_NEW: new UserPassUserNewPage(),
|
||||
USERPASS_USER_DELETE: new UserPassUserDeletePage(),
|
||||
|
||||
SECRETS_HOME: new SecretsHomePage(),
|
||||
|
||||
TOTP_VIEW: new TOTPViewPage(),
|
||||
TOTP_NEW: new TOTPNewPage(),
|
||||
TOTP_DELETE: new TOTPDeletePage(),
|
||||
|
||||
TRANSIT_VIEW: new TransitViewPage(),
|
||||
TRANSIT_NEW_KEY: new NewTransitKeyPage(),
|
||||
TRANSIT_VIEW_SECRET: new TransitViewSecretPage(),
|
||||
TRANSIT_ENCRYPT: new TransitEncryptPage(),
|
||||
TRANSIT_DECRYPT: new TransitDecryptPage(),
|
||||
TRANSIT_REWRAP: new TransitRewrapPage(),
|
||||
|
||||
KEY_VALUE_VIEW: new KeyValueViewPage(),
|
||||
KEY_VALUE_SECRET: new KeyValueSecretPage(),
|
||||
KEY_VALUE_VERSIONS: new KeyValueVersionsPage(),
|
||||
KEY_VALUE_NEW_SECRET: new KeyValueNewPage(),
|
||||
KEY_VALUE_DELETE: new KeyValueDeletePage(),
|
||||
KEY_VALUE_SECRET_EDIT: new KeyValueSecretEditPage(),
|
||||
|
||||
DELETE_SECRET_ENGINE: new DeleteSecretsEnginePage(),
|
||||
|
||||
NEW_SECRETS_ENGINE: new NewSecretsEnginePage(),
|
||||
NEW_KV_ENGINE: new NewKVEnginePage(),
|
||||
NEW_TOTP_ENGINE: new NewTOTPEnginePage(),
|
||||
NEW_TRANSIT_ENGINE: new NewTransitEnginePage(),
|
||||
};
|
||||
|
||||
// This should implement all o PageListType
|
||||
class PageList {
|
||||
constructor(pages: pagesList) {
|
||||
this.pages = pages;
|
||||
}
|
||||
|
||||
private pages: pagesList;
|
||||
|
||||
async getPageIDs(): Promise<string[]> {
|
||||
return getObjectKeys(this.pages);
|
||||
}
|
||||
async getPage(pageID: string): Promise<PageType> {
|
||||
return this.pages[pageID];
|
||||
}
|
||||
}
|
||||
|
||||
export const pageList = new PageList(allPages);
|
||||
//import { PageType } from "./pagerouter/PageType";
|
||||
//
|
||||
//import { AccessHomePage } from "./ui/pages/Access/AccessHome";
|
||||
//import { AuthHomePage } from "./ui/pages/Access/Auth/AuthHome";
|
||||
//import { AuthViewConfigPage } from "./ui/pages/Access/Auth/AuthViewConfig";
|
||||
//import { DeleteSecretsEnginePage } from "./ui/pages/Secrets/DeleteSecretsEngine";
|
||||
//import { HomePage } from "./ui/pages/Home";
|
||||
//import { KeyValueDeletePage } from "./ui/pages/Secrets/KeyValue/KeyValueDelete";
|
||||
//import { KeyValueNewPage } from "./ui/pages/Secrets/KeyValue/KeyValueNew";
|
||||
//import { KeyValueSecretEditPage } from "./ui/pages/Secrets/KeyValue/KeyValueSecretsEdit";
|
||||
//import { KeyValueSecretPage } from "./ui/pages/Secrets/KeyValue/KeyValueSecret";
|
||||
//import { KeyValueVersionsPage } from "./ui/pages/Secrets/KeyValue/KeyValueVersions";
|
||||
//import { KeyValueViewPage } from "./ui/pages/Secrets/KeyValue/KeyValueView";
|
||||
//import { LoginPage } from "./ui/pages/Login";
|
||||
//import { MePage } from "./ui/pages/Me";
|
||||
//import { NewKVEnginePage } from "./ui/pages/Secrets/NewEngines/NewKVEngine";
|
||||
//import { NewSecretsEnginePage } from "./ui/pages/Secrets/NewSecretsEngine";
|
||||
//import { NewTOTPEnginePage } from "./ui/pages/Secrets/NewEngines/NewTOTPEngine";
|
||||
//import { NewTransitEnginePage } from "./ui/pages/Secrets/NewEngines/NewTransitEngine";
|
||||
//import { NewTransitKeyPage } from "./ui/pages/Secrets/Transit/NewTransitKey";
|
||||
//import { Page } from "./types/Page";
|
||||
//import { PoliciesHomePage } from "./ui/pages/Policies/PoliciesHome";
|
||||
//import { PolicyDeletePage } from "./ui/pages/Policies/PolicyDelete";
|
||||
//import { PolicyEditPage } from "./ui/pages/Policies/PolicyEdit";
|
||||
//import { PolicyNewPage } from "./ui/pages/Policies/PolicyNew";
|
||||
//import { PolicyViewPage } from "./ui/pages/Policies/PolicyView";
|
||||
//import { PwGenPage } from "./ui/pages/PwGen";
|
||||
//import { SecretsHomePage } from "./ui/pages/Secrets/SecretsHome";
|
||||
//import { SetLanguagePage } from "./ui/pages/SetLanguage";
|
||||
//import { SetVaultURLPage } from "./ui/pages/SetVaultURL";
|
||||
//import { TOTPDeletePage } from "./ui/pages/Secrets/TOTP/TOTPDelete";
|
||||
//import { TOTPNewPage } from "./ui/pages/Secrets/TOTP/TOTPNew";
|
||||
//import { TOTPViewPage } from "./ui/pages/Secrets/TOTP/TOTPView";
|
||||
//import { TransitDecryptPage } from "./ui/pages/Secrets/Transit/TransitDecrypt";
|
||||
//import { TransitEncryptPage } from "./ui/pages/Secrets/Transit/TransitEncrypt";
|
||||
//import { TransitRewrapPage } from "./ui/pages/Secrets/Transit/TransitRewrap";
|
||||
//import { TransitViewPage } from "./ui/pages/Secrets/Transit/TransitView";
|
||||
//import { TransitViewSecretPage } from "./ui/pages/Secrets/Transit/TransitViewSecret";
|
||||
//import { UnsealPage } from "./ui/pages/Unseal";
|
||||
//import { UserPassUserDeletePage } from "./ui/pages/Access/Auth/userpass/UserPassUserDelete";
|
||||
//import { UserPassUserEditPage } from "./ui/pages/Access/Auth/userpass/UserPassUserEdit";
|
||||
//import { UserPassUserNewPage } from "./ui/pages/Access/Auth/userpass/UserPassUserNew";
|
||||
//import { UserPassUserViewPage } from "./ui/pages/Access/Auth/userpass/UserPassUserView";
|
||||
//import { UserPassUsersListPage } from "./ui/pages/Access/Auth/userpass/UserPassUsersList";
|
||||
//import { getObjectKeys } from "./utils";
|
||||
//
|
||||
//type pagesList = {
|
||||
// [key: string]: Page;
|
||||
//};
|
||||
//
|
||||
//export const allPages: pagesList = {
|
||||
// HOME: new HomePage(),
|
||||
// LOGIN: new LoginPage(),
|
||||
// SET_VAULT_URL: new SetVaultURLPage(),
|
||||
// UNSEAL: new UnsealPage(),
|
||||
// SET_LANGUAGE: new SetLanguagePage(),
|
||||
// ME: new MePage(),
|
||||
// PW_GEN: new PwGenPage(),
|
||||
//
|
||||
// POLICIES_HOME: new PoliciesHomePage(),
|
||||
// POLICY_VIEW: new PolicyViewPage(),
|
||||
// POLICY_NEW: new PolicyNewPage(),
|
||||
// POLICY_EDIT: new PolicyEditPage(),
|
||||
// POLICY_DELETE: new PolicyDeletePage(),
|
||||
//
|
||||
// ACCESS_HOME: new AccessHomePage(),
|
||||
//
|
||||
// AUTH_HOME: new AuthHomePage(),
|
||||
// AUTH_VIEW_CONFIG: new AuthViewConfigPage(),
|
||||
//
|
||||
// USERPASS_USERS_LIST: new UserPassUsersListPage(),
|
||||
// USERPASS_USER_VIEW: new UserPassUserViewPage(),
|
||||
// USERPASS_USER_EDIT: new UserPassUserEditPage(),
|
||||
// USERPASS_USER_NEW: new UserPassUserNewPage(),
|
||||
// USERPASS_USER_DELETE: new UserPassUserDeletePage(),
|
||||
//
|
||||
// SECRETS_HOME: new SecretsHomePage(),
|
||||
//
|
||||
// TOTP_VIEW: new TOTPViewPage(),
|
||||
// TOTP_NEW: new TOTPNewPage(),
|
||||
// TOTP_DELETE: new TOTPDeletePage(),
|
||||
//
|
||||
// TRANSIT_VIEW: new TransitViewPage(),
|
||||
// TRANSIT_NEW_KEY: new NewTransitKeyPage(),
|
||||
// TRANSIT_VIEW_SECRET: new TransitViewSecretPage(),
|
||||
// TRANSIT_ENCRYPT: new TransitEncryptPage(),
|
||||
// TRANSIT_DECRYPT: new TransitDecryptPage(),
|
||||
// TRANSIT_REWRAP: new TransitRewrapPage(),
|
||||
//
|
||||
// KEY_VALUE_VIEW: new KeyValueViewPage(),
|
||||
// KEY_VALUE_SECRET: new KeyValueSecretPage(),
|
||||
// KEY_VALUE_VERSIONS: new KeyValueVersionsPage(),
|
||||
// KEY_VALUE_NEW_SECRET: new KeyValueNewPage(),
|
||||
// KEY_VALUE_DELETE: new KeyValueDeletePage(),
|
||||
// KEY_VALUE_SECRET_EDIT: new KeyValueSecretEditPage(),
|
||||
//
|
||||
// DELETE_SECRET_ENGINE: new DeleteSecretsEnginePage(),
|
||||
//
|
||||
// NEW_SECRETS_ENGINE: new NewSecretsEnginePage(),
|
||||
// NEW_KV_ENGINE: new NewKVEnginePage(),
|
||||
// NEW_TOTP_ENGINE: new NewTOTPEnginePage(),
|
||||
// NEW_TRANSIT_ENGINE: new NewTransitEnginePage(),
|
||||
//};
|
||||
//
|
||||
//// This should implement all o PageListType
|
||||
//class PageList {
|
||||
// constructor(pages: pagesList) {
|
||||
// this.pages = pages;
|
||||
// }
|
||||
//
|
||||
// private pages: pagesList;
|
||||
//
|
||||
// async getPageIDs(): Promise<string[]> {
|
||||
// return getObjectKeys(this.pages);
|
||||
// }
|
||||
// async getPage(pageID: string): Promise<PageType> {
|
||||
// return this.pages[pageID];
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//export const pageList = new PageList(allPages);
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { appendAPIURL, checkResponse, getHeaders } from "../apiUtils";
|
||||
import { removeDoubleSlash } from "../../utils";
|
||||
import { getMount } from "../sys/getMounts";
|
||||
|
||||
export async function createOrUpdateSecret(
|
||||
baseMount: string,
|
||||
secretMountType: string,
|
||||
secretPath: string[],
|
||||
name: string,
|
||||
data: Record<string, unknown>,
|
||||
|
@ -11,7 +11,8 @@ export async function createOrUpdateSecret(
|
|||
let secretURL = "";
|
||||
let APIData = {};
|
||||
|
||||
if (secretMountType == "kv-v2") {
|
||||
const mountInfo = await getMount(baseMount);
|
||||
if (mountInfo.options.version == "2") {
|
||||
secretURL = `/v1/${baseMount}/data/${secretPath.join("/")}/${name}`;
|
||||
APIData = { data: data };
|
||||
} else {
|
||||
|
|
|
@ -1,30 +1,17 @@
|
|||
import { appendAPIURL, checkResponse, getHeaders } from "../apiUtils";
|
||||
import { removeDoubleSlash } from "../../utils";
|
||||
import { getMount } from "../sys/getMounts";
|
||||
|
||||
export async function deleteSecret(
|
||||
baseMount: string,
|
||||
secretMountType: string,
|
||||
secretPath: string[],
|
||||
name: string,
|
||||
version: string | null = null,
|
||||
): Promise<void> {
|
||||
let secretURL = "";
|
||||
|
||||
let request;
|
||||
|
||||
if (secretMountType == "kv-v2" && version != null) {
|
||||
secretURL = `/v1/${baseMount}/delete/${secretPath.join("")}/${name}`;
|
||||
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
|
||||
request = new Request(appendAPIURL(secretURL), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
...getHeaders(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: version != null ? JSON.stringify({ versions: [version] }) : "{}",
|
||||
});
|
||||
} else {
|
||||
if (secretMountType == "kv-v2") {
|
||||
const mountInfo = await getMount(baseMount);
|
||||
if (mountInfo.options.version == "2") {
|
||||
secretURL = `/v1/${baseMount}/metadata/${secretPath.join("")}/${name}`;
|
||||
} else {
|
||||
secretURL = `/v1/${baseMount}/${secretPath.join("")}/${name}`;
|
||||
|
@ -34,7 +21,6 @@ export async function deleteSecret(
|
|||
method: "DELETE",
|
||||
headers: getHeaders(),
|
||||
});
|
||||
}
|
||||
const resp = await fetch(request);
|
||||
await checkResponse(resp);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { appendAPIURL, checkResponse, getHeaders } from "../apiUtils";
|
||||
import { getMount } from "../sys/getMounts";
|
||||
|
||||
export async function getSecretKV1(
|
||||
baseMount: string,
|
||||
|
@ -21,12 +22,10 @@ export async function getSecretKV2(
|
|||
baseMount: string,
|
||||
secretPath: string[],
|
||||
name: string,
|
||||
version: string | null = null,
|
||||
): Promise<Record<string, unknown>> {
|
||||
let secretURL = "";
|
||||
|
||||
secretURL = `/v1/${baseMount}/data/${secretPath.join("")}/${name}`;
|
||||
if (version != null) secretURL += `?version=${version}`;
|
||||
|
||||
const request = new Request(appendAPIURL(secretURL), {
|
||||
headers: getHeaders(),
|
||||
|
@ -41,13 +40,12 @@ export async function getSecretKV2(
|
|||
|
||||
export async function getSecret(
|
||||
baseMount: string,
|
||||
secretMountType: string,
|
||||
secretPath: string[],
|
||||
name: string,
|
||||
version: string | null = null,
|
||||
): Promise<Record<string, unknown>> {
|
||||
if (secretMountType == "kv-v2") {
|
||||
return await getSecretKV2(baseMount, secretPath, name, version);
|
||||
const mountInfo = await getMount(baseMount);
|
||||
if (mountInfo.options.version == "2") {
|
||||
return await getSecretKV2(baseMount, secretPath, name);
|
||||
} else {
|
||||
return await getSecretKV1(baseMount, secretPath, name);
|
||||
}
|
||||
|
|
|
@ -2,10 +2,13 @@ import { appendAPIURL, checkResponse, getHeaders } from "../apiUtils";
|
|||
|
||||
export async function getSecrets(
|
||||
baseMount: string,
|
||||
secretMountType: string,
|
||||
secretPath: string[],
|
||||
): Promise<string[]> {
|
||||
let secretURL = "";
|
||||
|
||||
// TODO: FIX THIS
|
||||
let secretMountType = "kv-v2"
|
||||
|
||||
if (secretMountType == "kv-v2") {
|
||||
secretURL = `/v1/${baseMount}/metadata/${secretPath.join("")}?list=true`;
|
||||
} else {
|
||||
|
|
|
@ -21,3 +21,15 @@ export async function getMounts(): Promise<MountsType> {
|
|||
const data = (await resp.json()) as { data: { secret: MountsType } };
|
||||
return data.data.secret;
|
||||
}
|
||||
|
||||
export async function getMount(mountName: string): Promise<MountType> {
|
||||
const request = new Request(appendAPIURL("/v1/sys/internal/ui/mounts/" + mountName), {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
const resp = await fetch(request);
|
||||
await checkResponse(resp);
|
||||
|
||||
const data = (await resp.json()) as { data: MountType };
|
||||
return data.data;
|
||||
}
|
||||
|
||||
|
|
117
src/main.tsx
117
src/main.tsx
|
@ -25,59 +25,110 @@ import translations from "./translations/index.mjs";
|
|||
import { PageRouter } from "./pagerouter/PageRouter";
|
||||
import { formatDistance } from "./formatDistance";
|
||||
import { getSealStatus } from "./api/sys/getSealStatus";
|
||||
import { pageList } from "./allPages";
|
||||
//import { pageList } from "./allPages";
|
||||
import { pageState } from "./globalPageState";
|
||||
import { playground } from "./playground";
|
||||
import { reloadNavBar } from "./ui/elements/NavBar";
|
||||
import { render } from "preact";
|
||||
import { NavBar } from "./ui/elements/NavBar";
|
||||
import { render, Component } from "preact";
|
||||
import i18next from "i18next";
|
||||
import Router from 'preact-router';
|
||||
import { Home } from "./ui/pages/Home";
|
||||
import { Me } from "./ui/pages/Me";
|
||||
import { Login } from "./ui/pages/Login";
|
||||
import { PasswordGenerator } from "./ui/pages/PwGen";
|
||||
import { SetVaultURL } from "./ui/pages/SetVaultURL";
|
||||
import { Unseal } from "./ui/pages/Unseal";
|
||||
import { SetLanguage } from "./ui/pages/SetLanguage";
|
||||
import { Secrets } from "./ui/pages/Secrets/SecretsHome";
|
||||
import { TOTPView } from "./ui/pages/Secrets/TOTP/TOTPView";
|
||||
import { TOTPNew } from "./ui/pages/Secrets/TOTP/TOTPNew";
|
||||
import { TOTPDelete } from "./ui/pages/Secrets/TOTP/TOTPDelete";
|
||||
import { NewSecretsEngine } from "./ui/pages/Secrets/NewSecretsEngine";
|
||||
import { NewKVEngine } from "./ui/pages/Secrets/NewEngines/NewKVEngine";
|
||||
import { NewTOTPEngine } from "./ui/pages/Secrets/NewEngines/NewTOTPEngine";
|
||||
import { NewTransitEngine } from "./ui/pages/Secrets/NewEngines/NewTransitEngine";
|
||||
import { DeleteSecretsEngine } from "./ui/pages/Secrets/DeleteSecretsEngine";
|
||||
import { KeyValueView } from "./ui/pages/Secrets/KeyValue/KeyValueView";
|
||||
import { KeyValueSecret } from "./ui/pages/Secrets/KeyValue/KeyValueSecret";
|
||||
import { KeyValueSecretEdit } from "./ui/pages/Secrets/KeyValue/KeyValueSecretsEdit";
|
||||
import { KeyValueDelete } from "./ui/pages/Secrets/KeyValue/KeyValueDelete";
|
||||
|
||||
async function onLoad(): Promise<void> {
|
||||
const Main = () => (
|
||||
<Router>
|
||||
<Home path="/" state={pageState} />
|
||||
<Me path="/me" state={pageState} />
|
||||
<Login path="/login" state={pageState} />
|
||||
<PasswordGenerator path="/pw_gen" />
|
||||
<SetVaultURL path="/set_vault_url" state={pageState} />
|
||||
<Unseal path="/unseal" state={pageState} />
|
||||
<SetLanguage path="/set_language" state={pageState} />
|
||||
|
||||
<Secrets path="/secrets" state={pageState} />
|
||||
<DeleteSecretsEngine path="/secrets/delete_engine/:mount" state={pageState} />
|
||||
|
||||
<NewSecretsEngine path="/secrets/new_secrets_engine" />
|
||||
<NewKVEngine path="/secrets/new_secrets_engine/kv" />
|
||||
<NewTOTPEngine path="/secrets/new_secrets_engine/totp" />
|
||||
<NewTransitEngine path="/secrets/new_secrets_engine/trasit" />
|
||||
|
||||
<TOTPView path="/secrets/totp/list/:mount" state={pageState} />
|
||||
<TOTPNew path="/secrets/totp/new/:mount" state={pageState} />
|
||||
<TOTPDelete path="/secrets/totp/delete/:mount/:item" state={pageState} />
|
||||
|
||||
<KeyValueView path="/secrets/kv/list/:mount+" state={pageState} />
|
||||
<KeyValueSecret path="/secrets/kv/view/:item/:mount+" state={pageState} />
|
||||
<KeyValueSecretEdit path="/secrets/kv/edit/:item/:mount+" state={pageState} />
|
||||
<KeyValueDelete path="/secrets/kv/delete/:item/:mount+" state={pageState} />
|
||||
|
||||
<div default><p>PAGE NOT YET IMPLEMENTED</p></div>
|
||||
|
||||
</Router>
|
||||
);
|
||||
render(
|
||||
<>
|
||||
<div id="navBarBox" />
|
||||
<NavBar />
|
||||
<div class="uk-container uk-container-medium uk-align-center">
|
||||
<div class="uk-card uk-card-body">
|
||||
<h3 class="uk-card-title" id="pageTitle" />
|
||||
<div id="pageContent" />
|
||||
<Main />
|
||||
</div>
|
||||
</div>
|
||||
</>,
|
||||
document.body,
|
||||
);
|
||||
|
||||
const pageRouter = new PageRouter({
|
||||
pageList: pageList,
|
||||
state: pageState,
|
||||
pageTitleElement: document.querySelector("#pageTitle"),
|
||||
pageContentElement: document.querySelector("#pageContent"),
|
||||
resetElementContent: !true,
|
||||
onPageChange: async function () {
|
||||
pageState.currentPage = await pageRouter.getCurrentPageID();
|
||||
document.documentElement.dir = pageState.pageDirection;
|
||||
},
|
||||
});
|
||||
|
||||
reloadNavBar(pageRouter);
|
||||
//const pageRouter = new PageRouter({
|
||||
// pageList: pageList,
|
||||
// state: pageState,
|
||||
// pageTitleElement: document.querySelector("#pageTitle"),
|
||||
// pageContentElement: document.querySelector("#pageContent"),
|
||||
// resetElementContent: !true,
|
||||
// onPageChange: async function () {
|
||||
// pageState.currentPage = await pageRouter.getCurrentPageID();
|
||||
// document.documentElement.dir = pageState.pageDirection;
|
||||
// },
|
||||
//});
|
||||
//
|
||||
//reloadNavBar(pageRouter);
|
||||
|
||||
if (process.env.NODE_ENV == "development") {
|
||||
await playground(pageRouter);
|
||||
// await playground(pageRouter);
|
||||
}
|
||||
|
||||
await pageRouter.changePage(pageState.currentPage);
|
||||
//await pageRouter.changePage(pageState.currentPage);
|
||||
|
||||
setInterval(async () => {
|
||||
if ((await pageRouter.getCurrentPageID()) != "UNSEAL") {
|
||||
if (pageState.apiURL.length != 0) {
|
||||
return;
|
||||
}
|
||||
const sealStatus = await getSealStatus();
|
||||
if (sealStatus.sealed) {
|
||||
await pageRouter.changePage("UNSEAL");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, 5000);
|
||||
//setInterval(async () => {
|
||||
// if ((await pageRouter.getCurrentPageID()) != "UNSEAL") {
|
||||
// if (pageState.apiURL.length != 0) {
|
||||
// return;
|
||||
// }
|
||||
// const sealStatus = await getSealStatus();
|
||||
// if (sealStatus.sealed) {
|
||||
// await pageRouter.changePage("UNSEAL");
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
//}, 5000);
|
||||
}
|
||||
|
||||
document.addEventListener(
|
||||
|
|
|
@ -5,35 +5,36 @@ import { lookupSelf } from "./api/sys/lookupSelf";
|
|||
import ClipboardJS from "clipboard";
|
||||
import UIkit from "uikit";
|
||||
import i18next from "i18next";
|
||||
import { route } from "preact-router";
|
||||
|
||||
async function prePageChecksReal(router: PageRouter) {
|
||||
const state = router.state as PageState;
|
||||
async function prePageChecksReal(state: PageState) {
|
||||
if (state.language.length == 0) {
|
||||
await router.changePage("SET_LANGUAGE");
|
||||
route("/set_language", true);
|
||||
throw new Error("Language Not Set");
|
||||
}
|
||||
|
||||
if (!state.apiURL) {
|
||||
await router.changePage("SET_VAULT_URL");
|
||||
route("/set_vault_url", true);
|
||||
throw new Error("Vault URL Not Set");
|
||||
}
|
||||
|
||||
const sealStatus = await getSealStatus();
|
||||
if (sealStatus.sealed) {
|
||||
await router.changePage("UNSEAL");
|
||||
route("/unseal", true);
|
||||
throw new Error("Vault Sealed");
|
||||
}
|
||||
|
||||
try {
|
||||
await lookupSelf();
|
||||
} catch (e) {
|
||||
await router.changePage("LOGIN");
|
||||
route("/login", true);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
export async function prePageChecks(router: PageRouter): Promise<boolean> {
|
||||
export async function prePageChecks(state: PageState): Promise<boolean> {
|
||||
try {
|
||||
await prePageChecksReal(router);
|
||||
await prePageChecksReal(state);
|
||||
} catch (e) {
|
||||
console.log("OHNO", e);
|
||||
return false;
|
||||
|
|
1
src/translations/en.js
vendored
1
src/translations/en.js
vendored
|
@ -35,6 +35,7 @@ module.exports = {
|
|||
me_copy_token_btn: "Copy Token",
|
||||
me_renew_lease_btn: "Renew Token Lease",
|
||||
me_change_language_btn: "Change Language",
|
||||
me_set_vault_url_btn: "Set Vault URL",
|
||||
|
||||
// Home Page
|
||||
home_page_title: "Home",
|
||||
|
|
6
src/types/DefaultPageProps.ts
Normal file
6
src/types/DefaultPageProps.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { PageState } from "../state/PageState";
|
||||
|
||||
export type DefaultPageProps = {
|
||||
state: PageState;
|
||||
matches?: {[key: string]: string}
|
||||
};
|
|
@ -1,29 +1,24 @@
|
|||
import { JSX, render } from "preact";
|
||||
import { PageRouter } from "../../pagerouter/PageRouter";
|
||||
import i18next from "i18next";
|
||||
import { getCurrentUrl, route } from "preact-router";
|
||||
|
||||
export type NavBarProps = {
|
||||
router: PageRouter;
|
||||
};
|
||||
|
||||
export function NavBar(props: NavBarProps): JSX.Element {
|
||||
export function NavBar(): JSX.Element {
|
||||
return (
|
||||
<nav class="uk-navbar uk-navbar-container">
|
||||
<div class="uk-navbar-left">
|
||||
<ul class="uk-navbar-nav">
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await props.router.changePage("HOME");
|
||||
}}
|
||||
>
|
||||
<a href="/">
|
||||
{i18next.t("home_btn")}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await props.router.goBack();
|
||||
window.history.back()
|
||||
// maybe???
|
||||
}}
|
||||
>
|
||||
{i18next.t("back_btn")}
|
||||
|
@ -32,7 +27,7 @@ export function NavBar(props: NavBarProps): JSX.Element {
|
|||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await props.router.refresh();
|
||||
route(getCurrentUrl(), false);
|
||||
}}
|
||||
>
|
||||
{i18next.t("refresh_btn")}
|
||||
|
@ -45,7 +40,7 @@ export function NavBar(props: NavBarProps): JSX.Element {
|
|||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await props.router.changePage("ME");
|
||||
route("/me", true);
|
||||
}}
|
||||
>
|
||||
{i18next.t("me_btn")}
|
||||
|
@ -56,7 +51,3 @@ export function NavBar(props: NavBarProps): JSX.Element {
|
|||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
export function reloadNavBar(router: PageRouter): void {
|
||||
render(<NavBar router={router} />, document.querySelector("#navBarBox"));
|
||||
}
|
||||
|
|
9
src/ui/elements/PageTitle.tsx
Normal file
9
src/ui/elements/PageTitle.tsx
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { JSX } from "preact";
|
||||
|
||||
export type PageTitleProps = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
export function PageTitle(props: PageTitleProps): JSX.Element {
|
||||
return <h3 class="uk-card-title" id="pageTitle">{props.title}</h3>;
|
||||
}
|
|
@ -4,6 +4,7 @@ import { Tile } from "../../elements/Tile";
|
|||
import { notImplemented, prePageChecks } from "../../../pageUtils";
|
||||
import { render } from "preact";
|
||||
import i18next from "i18next";
|
||||
import { PageState } from "../../../state/PageState";
|
||||
|
||||
export class AccessHomePage extends Page {
|
||||
constructor() {
|
||||
|
@ -14,7 +15,7 @@ export class AccessHomePage extends Page {
|
|||
}
|
||||
async render(): Promise<void> {
|
||||
this.router.pageContentElement.innerHTML = "";
|
||||
if (!(await prePageChecks(this.router))) return;
|
||||
if (!(await prePageChecks(this.router.state as PageState))) return;
|
||||
|
||||
render(
|
||||
<Grid size={GridSizes.MATCHING_TWO_ROWS}>
|
||||
|
|
|
@ -6,21 +6,25 @@ import { TokenInfo } from "../../api/types/token";
|
|||
import { getCapabilitiesPath } from "../../api/sys/getCapabilities";
|
||||
import { lookupSelf } from "../../api/sys/lookupSelf";
|
||||
import { prePageChecks, setErrorText } from "../../pageUtils";
|
||||
import { render } from "preact";
|
||||
import { Component, JSX, render } from "preact";
|
||||
import i18next from "i18next";
|
||||
import { PageState } from "../../state/PageState";
|
||||
import { route } from "preact-router";
|
||||
import { PageTitle } from "../elements/PageTitle";
|
||||
|
||||
export class HomePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
await this.router.setPageContent("");
|
||||
if (!(await prePageChecks(this.router))) return;
|
||||
type HomeProps = {
|
||||
state: PageState;
|
||||
}
|
||||
|
||||
this.state.baseMount = "";
|
||||
this.state.secretPath = [];
|
||||
this.state.secretItem = "";
|
||||
this.state.secretVersion = null;
|
||||
type HomeState = {
|
||||
selfTokenInfo: TokenInfo;
|
||||
authCaps: string[];
|
||||
policiesCaps: string[];
|
||||
}
|
||||
|
||||
export class Home extends Component<HomeProps, HomeState> {
|
||||
async componentDidMount() {
|
||||
if (!(await prePageChecks(this.props.state))) return;
|
||||
|
||||
let selfTokenInfo: TokenInfo;
|
||||
try {
|
||||
|
@ -29,8 +33,9 @@ export class HomePage extends Page {
|
|||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
if (error.message == "permission denied") {
|
||||
this.state.token = "";
|
||||
await this.router.changePage("LOGIN");
|
||||
this.props.state.token = "";
|
||||
route('/login', true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,25 +43,31 @@ export class HomePage extends Page {
|
|||
const authCaps = caps["sys/auth"];
|
||||
const policiesCaps = caps["sys/policies"];
|
||||
|
||||
render(
|
||||
this.setState({
|
||||
selfTokenInfo: selfTokenInfo,
|
||||
authCaps: authCaps,
|
||||
policiesCaps: policiesCaps,
|
||||
})
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
return this.state.selfTokenInfo && (
|
||||
<>
|
||||
<PageTitle title={this.name} />
|
||||
<div>
|
||||
<ul id="textList" class="uk-nav">
|
||||
<li>
|
||||
<span>{i18next.t("home_vaulturl_text", { text: this.state.apiURL })}</span>
|
||||
<span>{i18next.t("home_vaulturl_text", { text: this.props.state.apiURL })}</span>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await this.router.changePage("PW_GEN");
|
||||
}}
|
||||
>
|
||||
<a href="/pw_gen">
|
||||
{i18next.t("home_password_generator_btn")}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<span>
|
||||
{i18next.t("home_your_token_expires_in", {
|
||||
date: new Date(selfTokenInfo.expire_time),
|
||||
date: new Date(this.state.selfTokenInfo.expire_time),
|
||||
})}
|
||||
</span>
|
||||
</li>
|
||||
|
@ -68,31 +79,31 @@ export class HomePage extends Page {
|
|||
description={i18next.t("home_secrets_description")}
|
||||
icon="file-edit"
|
||||
onclick={async () => {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
route("/secrets");
|
||||
}}
|
||||
/>
|
||||
<Tile
|
||||
title={i18next.t("home_access_title")}
|
||||
description={i18next.t("home_access_description")}
|
||||
icon="users"
|
||||
disabled={!authCaps.includes("read")}
|
||||
disabled={!this.state.authCaps.includes("read")}
|
||||
onclick={async () => {
|
||||
await this.router.changePage("ACCESS_HOME");
|
||||
route("/access");
|
||||
}}
|
||||
/>
|
||||
<Tile
|
||||
title={i18next.t("home_policies_title")}
|
||||
description={i18next.t("home_policies_description")}
|
||||
icon="pencil"
|
||||
disabled={!policiesCaps.includes("read")}
|
||||
disabled={!this.state.policiesCaps.includes("read")}
|
||||
onclick={async () => {
|
||||
await this.router.changePage("POLICIES_HOME");
|
||||
route("/policies");
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Margin>
|
||||
</div>,
|
||||
this.router.pageContentElement,
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,12 @@ import { lookupSelf } from "../../api/sys/lookupSelf";
|
|||
import { setErrorText } from "../../pageUtils";
|
||||
import { usernameLogin } from "../../api/auth/usernameLogin";
|
||||
import i18next from "i18next";
|
||||
import { route } from "preact-router";
|
||||
import { PageTitle } from "../elements/PageTitle";
|
||||
import { DefaultPageProps } from "../../types/DefaultPageProps";
|
||||
import { PageState } from "../../state/PageState";
|
||||
|
||||
export class TokenLoginForm extends Component<{ page: Page }, unknown> {
|
||||
export class TokenLoginForm extends Component<{state: PageState}, unknown> {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
@ -36,13 +40,12 @@ export class TokenLoginForm extends Component<{ page: Page }, unknown> {
|
|||
}
|
||||
|
||||
async onSubmit(data: FormData): Promise<void> {
|
||||
const page = this.props.page;
|
||||
const token = data.get("token");
|
||||
page.state.token = token as string;
|
||||
this.props.state.token = token as string;
|
||||
|
||||
try {
|
||||
await lookupSelf();
|
||||
await page.router.changePage("HOME");
|
||||
route("/");
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
document.querySelector("#tokenInput").classList.add("uk-form-danger");
|
||||
|
@ -55,7 +58,7 @@ export class TokenLoginForm extends Component<{ page: Page }, unknown> {
|
|||
}
|
||||
}
|
||||
|
||||
export class UsernameLoginForm extends Component<{ page: Page }, unknown> {
|
||||
export class UsernameLoginForm extends Component<{state: PageState}, unknown> {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
@ -93,15 +96,13 @@ export class UsernameLoginForm extends Component<{ page: Page }, unknown> {
|
|||
}
|
||||
|
||||
async onSubmit(data: FormData): Promise<void> {
|
||||
const page = this.props.page;
|
||||
|
||||
try {
|
||||
const res = await usernameLogin(
|
||||
data.get("username") as string,
|
||||
data.get("password") as string,
|
||||
);
|
||||
page.state.token = res;
|
||||
await page.router.changePage("HOME");
|
||||
this.props.state.token = res;
|
||||
route("/");
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
document.querySelector("#usernameInput").classList.add("uk-form-danger");
|
||||
|
@ -111,12 +112,11 @@ export class UsernameLoginForm extends Component<{ page: Page }, unknown> {
|
|||
}
|
||||
}
|
||||
|
||||
export class LoginPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class Login extends Component<DefaultPageProps> {
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={this.name} />
|
||||
<div>
|
||||
<ul class="uk-subnav uk-subnav-pill" uk-switcher=".switcher-container">
|
||||
<li>
|
||||
|
@ -129,14 +129,14 @@ export class LoginPage extends Page {
|
|||
<p id="errorText" class="uk-text-danger" />
|
||||
<ul class="uk-switcher uk-margin switcher-container">
|
||||
<li>
|
||||
<TokenLoginForm page={this} />
|
||||
<TokenLoginForm state={this.props.state} />
|
||||
</li>
|
||||
<li>
|
||||
<UsernameLoginForm page={this} />
|
||||
<UsernameLoginForm state={this.props.state} />
|
||||
</li>
|
||||
</ul>
|
||||
</div>,
|
||||
this.router.pageContentElement,
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { Component, JSX, createRef, render } from "preact";
|
||||
import { Page } from "../../types/Page";
|
||||
import { Component, JSX, createRef } from "preact";
|
||||
import { addClipboardNotifications, prePageChecks, setErrorText } from "../../pageUtils";
|
||||
import { getCapsPath } from "../../api/sys/getCapabilities";
|
||||
import { renewSelf } from "../../api/sys/renewSelf";
|
||||
import { sealVault } from "../../api/sys/sealVault";
|
||||
import ClipboardJS from "clipboard";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../types/DefaultPageProps";
|
||||
import { route } from "preact-router";
|
||||
import { PageTitle } from "../elements/PageTitle";
|
||||
|
||||
export class CopyLink extends Component<{ text: string; data: string }, unknown> {
|
||||
linkRef = createRef();
|
||||
|
@ -24,14 +26,23 @@ export class CopyLink extends Component<{ text: string; data: string }, unknown>
|
|||
}
|
||||
}
|
||||
|
||||
export class MePage extends Page {
|
||||
type MeState = {
|
||||
loaded: boolean;
|
||||
canSealVault: boolean;
|
||||
}
|
||||
|
||||
export class Me extends Component<DefaultPageProps, MeState> {
|
||||
defaultState = { loaded: false, canSealVault: false }
|
||||
constructor() {
|
||||
super();
|
||||
this.state = this.defaultState;
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
if (!(await prePageChecks(this.router))) return;
|
||||
componentWillUnmount() {
|
||||
this.setState(this.defaultState);
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
let canSealVault = false;
|
||||
try {
|
||||
const caps = await getCapsPath("sys/seal");
|
||||
|
@ -40,27 +51,36 @@ export class MePage extends Page {
|
|||
canSealVault = false;
|
||||
}
|
||||
|
||||
render(
|
||||
this.setState({
|
||||
loaded: true,
|
||||
canSealVault: canSealVault,
|
||||
});
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
return this.state.loaded && (
|
||||
<>
|
||||
<PageTitle title={this.name} />
|
||||
<ul class="uk-nav">
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
this.state.token = "";
|
||||
await this.router.changePage("HOME");
|
||||
this.props.state.token = "";
|
||||
route("/");
|
||||
}}
|
||||
>
|
||||
{i18next.t("me_log_out_btn")}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<CopyLink text={i18next.t("me_copy_token_btn")} data={this.state.token} />
|
||||
<CopyLink text={i18next.t("me_copy_token_btn")} data={this.props.state.token} />
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
try {
|
||||
await renewSelf();
|
||||
await this.router.changePage("HOME");
|
||||
route("/");
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
|
@ -70,12 +90,12 @@ export class MePage extends Page {
|
|||
{i18next.t("me_renew_lease_btn")}
|
||||
</a>
|
||||
</li>
|
||||
{canSealVault && (
|
||||
{this.state.canSealVault && (
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await sealVault();
|
||||
await this.router.changePage("UNSEAL");
|
||||
route("/unseal", true);
|
||||
}}
|
||||
>
|
||||
{i18next.t("me_seal_vault_btn")}
|
||||
|
@ -83,16 +103,17 @@ export class MePage extends Page {
|
|||
</li>
|
||||
)}
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await this.router.changePage("SET_LANGUAGE");
|
||||
}}
|
||||
>
|
||||
<a href="/set_language">
|
||||
{i18next.t("me_change_language_btn")}
|
||||
</a>
|
||||
</li>
|
||||
</ul>,
|
||||
this.router.pageContentElement,
|
||||
<li>
|
||||
<a href="/set_vault_url">
|
||||
{i18next.t("me_set_vault_url_btn")}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import { getPolicies } from "../../../api/sys/policies/getPolicies";
|
|||
import { prePageChecks } from "../../../pageUtils";
|
||||
import { render } from "preact";
|
||||
import i18next from "i18next";
|
||||
import { PageState } from "../../../state/PageState";
|
||||
|
||||
export class PoliciesHomePage extends Page {
|
||||
constructor() {
|
||||
|
@ -14,7 +15,7 @@ export class PoliciesHomePage extends Page {
|
|||
}
|
||||
async render(): Promise<void> {
|
||||
await this.router.setPageContent("");
|
||||
if (!(await prePageChecks(this.router))) return;
|
||||
if (!(await prePageChecks(this.router.state as PageState))) return;
|
||||
|
||||
let policies = await getPolicies();
|
||||
policies = policies.sort();
|
||||
|
|
|
@ -5,6 +5,7 @@ import { getPolicy } from "../../../api/sys/policies/getPolicy";
|
|||
import { prePageChecks } from "../../../pageUtils";
|
||||
import { render } from "preact";
|
||||
import i18next from "i18next";
|
||||
import { PageState } from "../../../state/PageState";
|
||||
|
||||
export class PolicyViewPage extends Page {
|
||||
constructor() {
|
||||
|
@ -15,7 +16,7 @@ export class PolicyViewPage extends Page {
|
|||
}
|
||||
async render(): Promise<void> {
|
||||
await this.router.setPageContent("");
|
||||
if (!(await prePageChecks(this.router))) return;
|
||||
if (!(await prePageChecks(this.router.state as PageState))) return;
|
||||
|
||||
const policy = await getPolicy(this.state.policyItem);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Component, JSX, createRef, render } from "preact";
|
||||
import { CopyableInputBox } from "../elements/CopyableInputBox";
|
||||
import { PageTitle } from "../elements/PageTitle";
|
||||
import { Form } from "../elements/Form";
|
||||
import { Margin } from "../elements/Margin";
|
||||
import { Page } from "../../types/Page";
|
||||
|
@ -51,7 +52,7 @@ type PasswordGeneratorState = {
|
|||
alphabet: string;
|
||||
};
|
||||
|
||||
export class PasswordGenerator extends Component<unknown, PasswordGeneratorState> {
|
||||
export class PasswordGenerator extends Component<{}, PasswordGeneratorState> {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
|
@ -89,6 +90,8 @@ export class PasswordGenerator extends Component<unknown, PasswordGeneratorState
|
|||
// createRef
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={i18next.t("password_generator_title")} />
|
||||
<Form onSubmit={() => this.onSubmit()}>
|
||||
<Margin>
|
||||
<h4>{this.getPasswordLengthText(this.state.length)}</h4>
|
||||
|
@ -134,20 +137,7 @@ export class PasswordGenerator extends Component<unknown, PasswordGeneratorState
|
|||
</button>
|
||||
</Margin>
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class PwGenPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(<PasswordGenerator />, this.router.pageContentElement);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("password_generator_title");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,19 @@ import { Form } from "../../elements/Form";
|
|||
import { MarginInline } from "../../elements/MarginInline";
|
||||
import { Page } from "../../../types/Page";
|
||||
import { deleteMount } from "../../../api/sys/deleteMount";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { setErrorText } from "../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../types/DefaultPageProps";
|
||||
import { PageTitle } from "../../elements/PageTitle";
|
||||
import { route } from "preact-router";
|
||||
|
||||
export class DeleteSecretsEnginePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
export class DeleteSecretsEngine extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={i18next.t("delete_secrets_engine_title", { mount: this.props.matches["mount"] })}/>
|
||||
<Form
|
||||
onSubmit={async () => {
|
||||
await this.onSubmit();
|
||||
|
@ -27,22 +29,18 @@ export class DeleteSecretsEnginePage extends Page {
|
|||
{i18next.t("delete_secrets_engine_delete_btn")}
|
||||
</button>
|
||||
</MarginInline>
|
||||
</Form>,
|
||||
this.router.pageContentElement,
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
async onSubmit(): Promise<void> {
|
||||
try {
|
||||
await deleteMount(this.state.baseMount);
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
await deleteMount(this.props.matches["mount"]);
|
||||
route("/secrets");
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("delete_secrets_engine_title", { mount: this.state.baseMount });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,54 +1,40 @@
|
|||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { deleteSecret } from "../../../../api/kv/deleteSecret";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { splitKVMount } from "./splitKVMount";
|
||||
|
||||
export class KeyValueDeletePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
if (this.state.secretVersion != null) {
|
||||
this.state.secretVersion = null;
|
||||
await this.router.changePage("KEY_VALUE_SECRET");
|
||||
} else {
|
||||
this.state.secretItem = "";
|
||||
await this.router.changePage("KEY_VALUE_VIEW");
|
||||
}
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class KeyValueDelete extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
const mount = this.props.matches["mount"];
|
||||
const mountSplit = splitKVMount(mount);
|
||||
const baseMount = mountSplit.baseMount;
|
||||
const secretPath = mountSplit.restOfMount;
|
||||
const item = this.props.matches["item"];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement type="kv" item={this.props.matches["item"]} mount={mount} suffix={i18next.t("kv_sec_edit_suffix")} />
|
||||
<div>
|
||||
<h5>{i18next.t("kv_delete_text")}</h5>
|
||||
<button
|
||||
class="uk-button uk-button-danger"
|
||||
onClick={async () => {
|
||||
await deleteSecret(
|
||||
this.state.baseMount,
|
||||
this.state.secretMountType,
|
||||
this.state.secretPath,
|
||||
this.state.secretItem,
|
||||
this.state.secretVersion,
|
||||
baseMount,
|
||||
secretPath.map((e) => e + "/"),
|
||||
item,
|
||||
);
|
||||
await this.goBack();
|
||||
window.history.back();
|
||||
}}
|
||||
>
|
||||
{i18next.t("kv_delete_btn")}
|
||||
</button>
|
||||
</div>,
|
||||
this.router.pageContentElement,
|
||||
);
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("kv_delete_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("kv_delete_title");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,6 @@ export class KeyValueNewPage extends Page {
|
|||
try {
|
||||
await createOrUpdateSecret(
|
||||
this.state.baseMount,
|
||||
this.state.secretMountType,
|
||||
this.state.secretPath,
|
||||
path,
|
||||
keyData,
|
||||
|
@ -61,12 +60,12 @@ export class KeyValueNewPage extends Page {
|
|||
}
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("kv_new_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(
|
||||
// <SecretTitleElement page={this} suffix={i18next.t("kv_new_suffix")} />,
|
||||
// this.router.pageTitleElement,
|
||||
// );
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("kv_new_title");
|
||||
|
|
|
@ -9,6 +9,10 @@ import { getSecret } from "../../../../api/kv/getSecret";
|
|||
import { sortedObjectMap } from "../../../../utils";
|
||||
import { undeleteSecret } from "../../../../api/kv/undeleteSecret";
|
||||
import i18next from "i18next";
|
||||
import { splitKVMount } from "./splitKVMount";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { getMount } from "../../../../api/sys/getMounts";
|
||||
import { route } from "preact-router";
|
||||
|
||||
export type KVSecretViewProps = {
|
||||
kvData: Record<string, unknown>;
|
||||
|
@ -41,119 +45,92 @@ export class KVSecretVew extends Component<KVSecretViewProps, unknown> {
|
|||
}
|
||||
}
|
||||
|
||||
export class KeyValueSecretPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
if (this.state.secretVersion != null) {
|
||||
this.state.secretVersion = null;
|
||||
await this.router.changePage("KEY_VALUE_VERSIONS");
|
||||
} else {
|
||||
this.state.secretItem = "";
|
||||
await this.router.changePage("KEY_VALUE_VIEW");
|
||||
}
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
type KeyValueSecretState = {
|
||||
baseMount: string;
|
||||
secretPath: string[];
|
||||
secretItem: string;
|
||||
caps: string[];
|
||||
secretInfo: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export class KeyValueSecret extends Component<DefaultPageProps, KeyValueSecretState> {
|
||||
async componentDidMount() {
|
||||
const mount = this.props.matches["mount"];
|
||||
const mountSplit = splitKVMount(mount);
|
||||
const baseMount = mountSplit.baseMount;
|
||||
const secretPath = mountSplit.restOfMount;
|
||||
const secretItem = this.props.matches["item"];
|
||||
|
||||
const caps = (
|
||||
await getCapabilities(this.state.baseMount, this.state.secretPath, this.state.secretItem)
|
||||
await getCapabilities(baseMount, secretPath, secretItem)
|
||||
).capabilities;
|
||||
|
||||
let secretPathAPI = secretPath.map((e) => e + "/");
|
||||
// TODO: this is a big hacky, fix when redo how api arguments work
|
||||
secretPathAPI[secretPathAPI.length - 1] = String(secretPathAPI[secretPathAPI.length - 1]).replace("/", "").toString();
|
||||
|
||||
const secretInfo = await getSecret(
|
||||
this.state.baseMount,
|
||||
this.state.secretMountType,
|
||||
this.state.secretPath,
|
||||
this.state.secretItem,
|
||||
this.state.secretVersion,
|
||||
baseMount,
|
||||
secretPathAPI,
|
||||
secretItem,
|
||||
);
|
||||
this.setState({
|
||||
baseMount,
|
||||
secretPath,
|
||||
secretItem,
|
||||
caps,
|
||||
secretInfo
|
||||
})
|
||||
|
||||
// On kv-v2, secrets can be deleted temporarily with the ability to restore
|
||||
// Do not show any buttons when the secret is deleted.
|
||||
const secretIsDeleted = secretInfo == null && this.state.secretMountType == "kv-v2";
|
||||
}
|
||||
render() {
|
||||
if (!this.state.baseMount) return;
|
||||
|
||||
render(
|
||||
// TODO: maybe add some sort of version viewing
|
||||
// no idea what gonna do for that
|
||||
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement type="kv" item={this.props.matches["item"]} mount={this.props.matches["mount"]} suffix={i18next.t("kv_sec_edit_suffix")} />
|
||||
<div>
|
||||
<p id="buttonsBlock">
|
||||
{
|
||||
// Delete Button
|
||||
!secretIsDeleted && caps.includes("delete") && (
|
||||
this.state.caps.includes("delete") && (
|
||||
<button
|
||||
class="uk-button uk-button-danger"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("KEY_VALUE_DELETE");
|
||||
route("/secrets/kv/delete/" + this.state.secretItem + "/" + this.state.baseMount + "/" + this.state.secretPath.join("/"))
|
||||
//await this.router.changePage("KEY_VALUE_DELETE");
|
||||
}}
|
||||
>
|
||||
{((): string => {
|
||||
// Delete Secret on kv-v1
|
||||
let deleteButtonText = i18next.t("kv_secret_delete_btn");
|
||||
if (this.state.secretMountType == "kv-v2" && this.state.secretVersion == null) {
|
||||
// Delete All
|
||||
deleteButtonText = i18next.t("kv_secret_delete_all_btn");
|
||||
} else if (
|
||||
this.state.secretMountType == "kv-v2" &&
|
||||
this.state.secretVersion != null
|
||||
) {
|
||||
// Delete Version X
|
||||
deleteButtonText = i18next.t("kv_secret_delete_version_btn", {
|
||||
version: this.state.secretVersion,
|
||||
});
|
||||
}
|
||||
return deleteButtonText;
|
||||
})()}
|
||||
{i18next.t("kv_secret_delete_btn")}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
{!secretIsDeleted && caps.includes("update") && this.state.secretVersion == null && (
|
||||
{this.state.caps.includes("update") && (
|
||||
<button
|
||||
class="uk-button uk-button-primary"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("KEY_VALUE_SECRET_EDIT");
|
||||
route("/secrets/kv/edit/" + this.state.secretItem + "/" + this.state.baseMount + "/" + this.state.secretPath.join("/"))
|
||||
}}
|
||||
>
|
||||
{i18next.t("kv_secret_edit_btn")}
|
||||
</button>
|
||||
)}
|
||||
{!secretIsDeleted && this.state.secretMountType == "kv-v2" && (
|
||||
<button
|
||||
class="uk-button uk-button-secondary"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("KEY_VALUE_VERSIONS");
|
||||
}}
|
||||
>
|
||||
{i18next.t("kv_secret_versions_btn")}
|
||||
</button>
|
||||
)}
|
||||
</p>
|
||||
|
||||
{!secretIsDeleted && <KVSecretVew kvData={secretInfo} />}
|
||||
|
||||
{secretIsDeleted && (
|
||||
<>
|
||||
<p>{i18next.t("kv_secret_deleted_text")}</p>
|
||||
<button
|
||||
class="uk-button uk-button-primary"
|
||||
onClick={async () => {
|
||||
await undeleteSecret(
|
||||
this.state.baseMount,
|
||||
this.state.secretPath,
|
||||
this.state.secretItem,
|
||||
this.state.secretVersion,
|
||||
);
|
||||
await this.router.refresh();
|
||||
}}
|
||||
>
|
||||
{i18next.t("kv_secret_restore_btn")}
|
||||
</button>
|
||||
{<KVSecretVew kvData={this.state.secretInfo} />}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>,
|
||||
this.router.pageContentElement,
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(<SecretTitleElement page={this} />, this.router.pageTitleElement);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(<SecretTitleElement page={this} />, this.router.pageTitleElement);
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("kv_secret_title");
|
||||
|
|
|
@ -7,10 +7,15 @@ import { getSecret } from "../../../../api/kv/getSecret";
|
|||
import { setErrorText } from "../../../../pageUtils";
|
||||
import { sortedObjectMap, verifyJSONString } from "../../../../utils";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { splitKVMount } from "./splitKVMount";
|
||||
import { route } from "preact-router";
|
||||
//import { highlightElement } from "prismjs";
|
||||
|
||||
export type KVEditProps = {
|
||||
page: Page;
|
||||
baseMount: string;
|
||||
secretPath: string[];
|
||||
secretItem: string;
|
||||
};
|
||||
|
||||
type KVEditState =
|
||||
|
@ -41,13 +46,12 @@ export class KVEditor extends Component<KVEditProps, KVEditState> {
|
|||
}
|
||||
|
||||
await createOrUpdateSecret(
|
||||
this.props.page.state.baseMount,
|
||||
this.props.page.state.secretMountType,
|
||||
this.props.page.state.secretPath,
|
||||
this.props.page.state.secretItem,
|
||||
this.props.baseMount,
|
||||
this.props.secretPath.map((e) => e + "/"),
|
||||
this.props.secretItem,
|
||||
JSON.parse(editorContent),
|
||||
);
|
||||
await this.props.page.router.changePage("KEY_VALUE_SECRET");
|
||||
window.history.back();
|
||||
}
|
||||
|
||||
onCodeUpdate(code: string): void {
|
||||
|
@ -58,10 +62,9 @@ export class KVEditor extends Component<KVEditProps, KVEditState> {
|
|||
|
||||
loadData(): void {
|
||||
void getSecret(
|
||||
this.props.page.state.baseMount,
|
||||
this.props.page.state.secretMountType,
|
||||
this.props.page.state.secretPath,
|
||||
this.props.page.state.secretItem,
|
||||
this.props.baseMount,
|
||||
this.props.secretPath.map((e) => e + "/"),
|
||||
this.props.secretItem,
|
||||
).then((kvData) => {
|
||||
this.setState({
|
||||
dataLoaded: true,
|
||||
|
@ -104,24 +107,29 @@ export class KVEditor extends Component<KVEditProps, KVEditState> {
|
|||
}
|
||||
}
|
||||
|
||||
export class KeyValueSecretEditPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("KEY_VALUE_SECRET");
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(<KVEditor page={this} />, this.router.pageContentElement);
|
||||
}
|
||||
export class KeyValueSecretEdit extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
const mount = this.props.matches["mount"];
|
||||
const mountSplit = splitKVMount(mount);
|
||||
const baseMount = mountSplit.baseMount;
|
||||
const restOfMount = mountSplit.restOfMount;
|
||||
const item = this.props.matches["item"];
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("kv_sec_edit_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement type="kv" mount={mount} item={this.props.matches["item"]} suffix={i18next.t("kv_sec_edit_suffix")} />
|
||||
<KVEditor baseMount={baseMount} secretPath={restOfMount} secretItem={item} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(
|
||||
// <SecretTitleElement page={this} suffix={i18next.t("kv_sec_edit_suffix")} />,
|
||||
// this.router.pageTitleElement,
|
||||
// );
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("kv_sec_edit_title");
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { getSecretMetadata } from "../../../../api/kv/getSecretMetadata";
|
||||
import { objectToMap } from "../../../../utils";
|
||||
import { render } from "preact";
|
||||
import i18next from "i18next";
|
||||
|
||||
export class KeyValueVersionsPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
if (this.state.secretVersion != null) {
|
||||
this.state.secretVersion = null;
|
||||
}
|
||||
await this.router.changePage("KEY_VALUE_SECRET");
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
const metadata = await getSecretMetadata(
|
||||
this.state.baseMount,
|
||||
this.state.secretPath,
|
||||
this.state.secretItem,
|
||||
);
|
||||
const versions = Array.from(objectToMap(metadata.versions).keys());
|
||||
|
||||
render(
|
||||
<ul class="uk-nav uk-nav-default">
|
||||
{versions.map((ver) => (
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
this.state.secretVersion = ver;
|
||||
await this.router.changePage("KEY_VALUE_SECRET");
|
||||
}}
|
||||
>
|
||||
{`v${ver}`}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>,
|
||||
this.router.pageContentElement,
|
||||
);
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("kv_sec_versions_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("kv_sec_versions_title");
|
||||
}
|
||||
}
|
|
@ -2,15 +2,17 @@ import { Component, createRef, JSX, render } from "preact";
|
|||
import { DoesNotExistError } from "../../../../types/internalErrors";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { getCapabilitiesPath } from "../../../../api/sys/getCapabilities";
|
||||
import { CapabilitiesType, getCapabilitiesPath } from "../../../../api/sys/getCapabilities";
|
||||
import { getSecrets } from "../../../../api/kv/getSecrets";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { route } from "preact-router";
|
||||
import { splitKVMount } from "./splitKVMount";
|
||||
|
||||
export type KVKeysListProps = {
|
||||
page: Page;
|
||||
|
||||
export type KVKeysListProps = DefaultPageProps & {
|
||||
baseMount: string;
|
||||
secretMountType: string;
|
||||
secretPath: string[];
|
||||
};
|
||||
|
||||
|
@ -20,17 +22,15 @@ type KVKeysListState = {
|
|||
searchQuery: string;
|
||||
};
|
||||
|
||||
function SecretsList(secrets: string[], page: Page): JSX.Element[] {
|
||||
function SecretsList(baseMount: string, restOfMount: string[], secrets: string[]): JSX.Element[] {
|
||||
return secrets.map((secret) => (
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
if (secret.endsWith("/")) {
|
||||
page.state.pushSecretPath(secret);
|
||||
await page.router.changePage("KEY_VALUE_VIEW");
|
||||
route("/secrets/kv/list/" + baseMount + "/" + restOfMount.join("/") + "/" + secret)
|
||||
} else {
|
||||
page.state.secretItem = secret;
|
||||
await page.router.changePage("KEY_VALUE_SECRET");
|
||||
route("/secrets/kv/view/" + secret + "/" + baseMount + "/" + restOfMount.join("/"))
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
@ -51,12 +51,10 @@ export class KVKeysList extends Component<KVKeysListProps, KVKeysListState> {
|
|||
}
|
||||
|
||||
async loadData(): Promise<void> {
|
||||
const page = this.props.page;
|
||||
try {
|
||||
const keys = await getSecrets(
|
||||
this.props.baseMount,
|
||||
this.props.secretMountType,
|
||||
this.props.secretPath,
|
||||
this.props.secretPath.map((e) => e + "/"),
|
||||
);
|
||||
this.setState({
|
||||
dataLoaded: true,
|
||||
|
@ -68,12 +66,13 @@ export class KVKeysList extends Component<KVKeysListProps, KVKeysListState> {
|
|||
if (error == DoesNotExistError) {
|
||||
// getSecrets also 404's on no keys so dont go all the way back.
|
||||
if (this.props.secretPath.length != 0) {
|
||||
await page.goBack();
|
||||
window.history.back();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
setErrorText(error.message);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
dataLoaded: true,
|
||||
keys: null,
|
||||
|
@ -84,7 +83,6 @@ export class KVKeysList extends Component<KVKeysListProps, KVKeysListState> {
|
|||
componentDidUpdate(prevProps: KVKeysListProps): void {
|
||||
if (
|
||||
prevProps.baseMount !== this.props.baseMount ||
|
||||
prevProps.secretMountType !== this.props.secretMountType ||
|
||||
prevProps.secretPath !== this.props.secretPath
|
||||
) {
|
||||
this.setState({
|
||||
|
@ -131,7 +129,7 @@ export class KVKeysList extends Component<KVKeysListProps, KVKeysListState> {
|
|||
if (this.state.searchQuery.length > 0) {
|
||||
secrets = secrets.filter((secret) => secret.includes(this.state.searchQuery));
|
||||
}
|
||||
return SecretsList(secrets, this.props.page);
|
||||
return SecretsList(this.props.baseMount, this.props.secretPath, secrets);
|
||||
})()}
|
||||
</ul>
|
||||
</>
|
||||
|
@ -139,65 +137,66 @@ export class KVKeysList extends Component<KVKeysListProps, KVKeysListState> {
|
|||
}
|
||||
}
|
||||
|
||||
export class KeyValueViewPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
if (this.state.secretPath.length != 0) {
|
||||
this.state.popSecretPath();
|
||||
await this.router.changePage("KEY_VALUE_VIEW");
|
||||
} else {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
}
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
const mountsPath = "/sys/mounts/" + this.state.baseMount;
|
||||
const currentPath = this.state.baseMount + this.state.secretPath.join("/");
|
||||
const caps = await getCapabilitiesPath([mountsPath, currentPath]);
|
||||
const mountCaps = caps[mountsPath];
|
||||
const pathCaps = caps[currentPath];
|
||||
type KeyValueViewState = {
|
||||
pathCaps: string[];
|
||||
mountCaps: string[];
|
||||
}
|
||||
|
||||
render(
|
||||
export class KeyValueView extends Component<DefaultPageProps, KeyValueViewState> {
|
||||
async componentDidMount() {
|
||||
const mount = this.props.matches["mount"];
|
||||
const mountSplit = splitKVMount(mount);
|
||||
const baseMount = mountSplit.baseMount;
|
||||
const restOfMount = mountSplit.restOfMount;
|
||||
|
||||
const mountsPath = "/sys/mounts/" + baseMount;
|
||||
const currentPath = baseMount + restOfMount.join();
|
||||
const caps = await getCapabilitiesPath([mountsPath, currentPath]);
|
||||
this.setState({
|
||||
mountCaps: caps[mountsPath],
|
||||
pathCaps: caps[currentPath],
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.state.pathCaps) return;
|
||||
|
||||
const mount = this.props.matches["mount"];
|
||||
const mountSplit = splitKVMount(mount);
|
||||
const baseMount = mountSplit.baseMount;
|
||||
const restOfMount = mountSplit.restOfMount;
|
||||
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement type="kv" mount={mount} item={this.props.matches["item"]} />
|
||||
<p>
|
||||
{pathCaps.includes("create") && (
|
||||
{this.state.pathCaps.includes("create") && (
|
||||
<button
|
||||
class="uk-button uk-button-primary"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("KEY_VALUE_NEW_SECRET");
|
||||
route("/secrets/kv/new/" + mount)
|
||||
}}
|
||||
>
|
||||
{i18next.t("kv_view_new_btn")}
|
||||
</button>
|
||||
)}
|
||||
{this.state.secretPath.length == 0 && mountCaps.includes("delete") && (
|
||||
{restOfMount.length == 0 && this.state.mountCaps.includes("delete") && (
|
||||
<button
|
||||
class="uk-button uk-button-danger"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("DELETE_SECRET_ENGINE");
|
||||
route("/secrets/delete_engine/" + mount)
|
||||
}}
|
||||
>
|
||||
{i18next.t("kv_view_delete_btn")}
|
||||
</button>
|
||||
)}
|
||||
</p>
|
||||
{this.state.secretMountType == "cubbyhole" && <p>{i18next.t("kv_view_cubbyhole_text")}</p>}
|
||||
<KVKeysList
|
||||
page={this}
|
||||
baseMount={this.state.baseMount}
|
||||
secretMountType={this.state.secretMountType}
|
||||
secretPath={this.state.secretPath}
|
||||
/>
|
||||
</>,
|
||||
this.router.pageContentElement,
|
||||
{//"TODO: " == "cubbyhole" && <p>{i18next.t("kv_view_cubbyhole_text")}</p>}
|
||||
}
|
||||
<KVKeysList baseMount={baseMount} secretPath={restOfMount} state={this.props.state} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(<SecretTitleElement page={this} />, this.router.pageTitleElement);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("kv_view_title");
|
||||
}
|
||||
|
|
10
src/ui/pages/Secrets/KeyValue/splitKVMount.tsx
Normal file
10
src/ui/pages/Secrets/KeyValue/splitKVMount.tsx
Normal file
|
@ -0,0 +1,10 @@
|
|||
export function splitKVMount(mount: string): { baseMount: string, restOfMount: string[] } {
|
||||
const baseMount = mount.split("/")[0];
|
||||
const restOfMount = mount.split("/");
|
||||
restOfMount.shift();
|
||||
|
||||
return {
|
||||
baseMount,
|
||||
restOfMount
|
||||
};
|
||||
}
|
|
@ -3,19 +3,17 @@ import { Margin } from "../../../elements/Margin";
|
|||
import { MarginInline } from "../../../elements/MarginInline";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { newMount } from "../../../../api/sys/newMount";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
import { PageTitle } from "../../../elements/PageTitle";
|
||||
import { route } from "preact-router";
|
||||
|
||||
export class NewKVEnginePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class NewKVEngine extends Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={i18next.t("new_kv_engine_title")} />
|
||||
<Form onSubmit={(data) => this.submit(data)}>
|
||||
<Margin>
|
||||
<input
|
||||
|
@ -42,8 +40,8 @@ export class NewKVEnginePage extends Page {
|
|||
{i18next.t("new_kv_engine_create_btn")}
|
||||
</button>
|
||||
</MarginInline>
|
||||
</Form>,
|
||||
this.router.pageContentElement,
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -59,16 +57,10 @@ export class NewKVEnginePage extends Page {
|
|||
version: version,
|
||||
},
|
||||
});
|
||||
this.state.secretMountType = "kv-v" + version;
|
||||
this.state.baseMount = name + "/";
|
||||
await this.router.changePage("KEY_VALUE_VIEW");
|
||||
route("/secrets/kv/list/" + name + "/")
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("new_kv_engine_title");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,19 +3,17 @@ import { Margin } from "../../../elements/Margin";
|
|||
import { MarginInline } from "../../../elements/MarginInline";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { newMount } from "../../../../api/sys/newMount";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
import { route } from "preact-router";
|
||||
import { PageTitle } from "../../../elements/PageTitle";
|
||||
|
||||
export class NewTOTPEnginePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class NewTOTPEngine extends Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={i18next.t("new_totp_engine_title")} />
|
||||
<Form onSubmit={(data) => this.submit(data)}>
|
||||
<Margin>
|
||||
<input
|
||||
|
@ -33,7 +31,7 @@ export class NewTOTPEnginePage extends Page {
|
|||
</button>
|
||||
</MarginInline>
|
||||
</Form>,
|
||||
this.router.pageContentElement,
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -45,9 +43,7 @@ export class NewTOTPEnginePage extends Page {
|
|||
name: name,
|
||||
type: "totp",
|
||||
});
|
||||
this.state.secretMountType = "totp";
|
||||
this.state.baseMount = name + "/";
|
||||
await this.router.changePage("TOTP_VIEW");
|
||||
route("/secrets/totp/list/" + name + "/")
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
|
|
|
@ -3,19 +3,17 @@ import { Margin } from "../../../elements/Margin";
|
|||
import { MarginInline } from "../../../elements/MarginInline";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { newMount } from "../../../../api/sys/newMount";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
import { PageTitle } from "../../../elements/PageTitle";
|
||||
import { route } from "preact-router";
|
||||
|
||||
export class NewTransitEnginePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class NewTransitEngine extends Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={i18next.t("new_totp_engine_title")} />
|
||||
<Form onSubmit={(data) => this.submit(data)}>
|
||||
<Margin>
|
||||
<input
|
||||
|
@ -33,7 +31,7 @@ export class NewTransitEnginePage extends Page {
|
|||
</button>
|
||||
</MarginInline>
|
||||
</Form>,
|
||||
this.router.pageContentElement,
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -45,9 +43,7 @@ export class NewTransitEnginePage extends Page {
|
|||
name: name,
|
||||
type: "transit",
|
||||
});
|
||||
this.state.secretMountType = "transit";
|
||||
this.state.baseMount = name + "/";
|
||||
await this.router.changePage("TRANSIT_VIEW");
|
||||
route("/secrets/transit/list/" + name + "/")
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
|
|
|
@ -1,44 +1,40 @@
|
|||
import { Grid, GridSizes } from "../../elements/Grid";
|
||||
import { Page } from "../../../types/Page";
|
||||
import { Tile } from "../../elements/Tile";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import i18next from "i18next";
|
||||
import { route } from "preact-router";
|
||||
import { PageTitle } from "../../elements/PageTitle";
|
||||
|
||||
export class NewSecretsEnginePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class NewSecretsEngine extends Component {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={i18next.t("new_secrets_engine_title")} />
|
||||
<Grid size={GridSizes.MATCHING_TWO_ROWS}>
|
||||
<Tile
|
||||
title={i18next.t("new_secrets_engine_kv_title")}
|
||||
description={i18next.t("new_secrets_engine_kv_description")}
|
||||
onclick={async () => {
|
||||
await this.router.changePage("NEW_KV_ENGINE");
|
||||
route("/secrets/new_secrets_engine/kv")
|
||||
}}
|
||||
/>
|
||||
<Tile
|
||||
title={i18next.t("new_secrets_engine_totp_title")}
|
||||
description={i18next.t("new_secrets_engine_totp_description")}
|
||||
onclick={async () => {
|
||||
await this.router.changePage("NEW_TOTP_ENGINE");
|
||||
route("/secrets/new_secrets_engine/totp")
|
||||
}}
|
||||
/>
|
||||
<Tile
|
||||
title={i18next.t("new_secrets_engine_transit_title")}
|
||||
description={i18next.t("new_secrets_engine_transit_description")}
|
||||
onclick={async () => {
|
||||
await this.router.changePage("NEW_TRANSIT_ENGINE");
|
||||
route("/secrets/new_secrets_engine/transit")
|
||||
}}
|
||||
/>
|
||||
</Grid>,
|
||||
this.router.pageContentElement,
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("new_secrets_engine_title");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,69 +1,55 @@
|
|||
import { route } from "preact-router";
|
||||
import { JSX } from "preact/jsx-runtime";
|
||||
import { Page } from "../../../types/Page";
|
||||
import { CopyStateLinkButton } from "../../elements/CopyStateLinkButton";
|
||||
|
||||
|
||||
function currentTitleSecretText(page: Page): string {
|
||||
let secretItemText = page.state.secretItem;
|
||||
if (page.state.secretVersion !== null) secretItemText += ` (v${page.state.secretVersion})`;
|
||||
return secretItemText;
|
||||
}
|
||||
|
||||
type SecretTitleElementProps = {
|
||||
page: Page;
|
||||
type: string;
|
||||
mount: string;
|
||||
item?: string;
|
||||
suffix?: string;
|
||||
};
|
||||
|
||||
export function SecretTitleElement(props: SecretTitleElementProps): JSX.Element {
|
||||
const page = props.page;
|
||||
const type = props.type;
|
||||
const mount = props.mount;
|
||||
const item = props.item || "";
|
||||
const suffix = props.suffix || "";
|
||||
|
||||
const baseMount = mount.split("/")[0];
|
||||
const restOfMount = mount.split("/");
|
||||
restOfMount.shift();
|
||||
|
||||
|
||||
return (
|
||||
<h3 class="uk-card-title" id="pageTitle">
|
||||
|
||||
<div>
|
||||
<a
|
||||
onClick={async () => {
|
||||
await page.router.changePage("SECRETS_HOME");
|
||||
route("/secrets");
|
||||
}}
|
||||
>
|
||||
{"/ "}
|
||||
</a>
|
||||
|
||||
<a
|
||||
onClick={async () => {
|
||||
page.state.secretPath = [];
|
||||
page.state.secretItem = "";
|
||||
page.state.secretVersion = null;
|
||||
|
||||
if (
|
||||
page.state.secretMountType.startsWith("kv") ||
|
||||
page.state.secretMountType == "cubbyhole"
|
||||
) {
|
||||
await page.router.changePage("KEY_VALUE_VIEW");
|
||||
} else if (page.state.secretMountType == "totp") {
|
||||
await page.router.changePage("TOTP_VIEW");
|
||||
} else if (page.state.secretMountType == "transit") {
|
||||
await page.router.changePage("TRANSIT_VIEW");
|
||||
}
|
||||
}}
|
||||
>
|
||||
{page.state.baseMount + " "}
|
||||
<a href={"/secrets/" + type + "/list/" + baseMount + "/"}>
|
||||
{baseMount + " "}
|
||||
</a>
|
||||
{...page.state.secretPath.map((secretPath, index, secretPaths) => (
|
||||
|
||||
{...restOfMount.map((secretPath, index, secretPaths) => (
|
||||
<a
|
||||
onClick={async () => {
|
||||
page.state.secretVersion = null;
|
||||
if (page.state.secretMountType.startsWith("kv")) {
|
||||
page.state.secretPath = secretPaths.slice(0, index + 1);
|
||||
await page.router.changePage("KEY_VALUE_VIEW");
|
||||
if (type == "kv") {
|
||||
let secretPath = secretPaths.slice(0, index + 1);
|
||||
route("/secrets/kv/list/" + baseMount + "/" + secretPath.join("/"))
|
||||
}
|
||||
}}
|
||||
>
|
||||
{secretPath + " "}
|
||||
{secretPath + "/" + " "}
|
||||
</a>
|
||||
))}
|
||||
{page.state.secretItem.length != 0 && <span>{currentTitleSecretText(page)}</span>}
|
||||
{item.length != 0 && <span>{item}</span>}
|
||||
{suffix.length != 0 && <span>{suffix}</span>}
|
||||
<CopyStateLinkButton state={page.state} />
|
||||
</div>
|
||||
</h3>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import { JSX, render } from "preact";
|
||||
import { Component, JSX, render } from "preact";
|
||||
import { MountType, getMounts } from "../../../api/sys/getMounts";
|
||||
import { Page } from "../../../types/Page";
|
||||
import { getCapsPath } from "../../../api/sys/getCapabilities";
|
||||
import { prePageChecks } from "../../../pageUtils";
|
||||
import { sortedObjectMap } from "../../../utils";
|
||||
import i18next from "i18next";
|
||||
|
||||
export type MountLinkProps = {
|
||||
page: Page;
|
||||
mount: MountType;
|
||||
baseMount: string;
|
||||
};
|
||||
import { PageState } from "../../../state/PageState";
|
||||
import { DefaultPageProps } from "../../../types/DefaultPageProps";
|
||||
import { route } from "preact-router";
|
||||
import { PageTitle } from "../../elements/PageTitle";
|
||||
|
||||
const supportedMountTypes = ["kv", "totp", "transit", "cubbyhole"];
|
||||
|
||||
|
@ -22,73 +20,75 @@ export function isSupportedMount(mount: MountType): boolean {
|
|||
return true;
|
||||
}
|
||||
|
||||
export type MountLinkProps = {
|
||||
state: PageState;
|
||||
mount: MountType;
|
||||
baseMount: string;
|
||||
};
|
||||
|
||||
function MountLink(props: MountLinkProps): JSX.Element {
|
||||
const mount = props.mount;
|
||||
const baseMount = props.baseMount;
|
||||
const page = props.page;
|
||||
|
||||
const secretMountType = mount.type == "kv" ? "kv-v" + String(mount.options.version) : mount.type;
|
||||
|
||||
let linkText = "";
|
||||
let linkPage: string;
|
||||
let mountPathType: string;
|
||||
if (mount.type == "kv") {
|
||||
linkText = `K/V (v${mount.options.version}) - ${baseMount}`;
|
||||
linkPage = "KEY_VALUE_VIEW";
|
||||
mountPathType = "kv";
|
||||
} else if (mount.type == "totp") {
|
||||
linkText = `TOTP - ${baseMount}`;
|
||||
linkPage = "TOTP_VIEW";
|
||||
mountPathType = "totp";
|
||||
} else if (mount.type == "transit") {
|
||||
linkText = `Transit - ${baseMount}`;
|
||||
linkPage = "TRANSIT_VIEW";
|
||||
mountPathType = "transit";
|
||||
} else if (mount.type == "cubbyhole") {
|
||||
linkText = `Cubbyhole - ${baseMount}`;
|
||||
linkPage = "KEY_VALUE_VIEW";
|
||||
mountPathType = "kv";
|
||||
}
|
||||
|
||||
let link = "/secrets/" + mountPathType + "/list/" + baseMount;
|
||||
|
||||
return (
|
||||
<li>
|
||||
<a
|
||||
onClick={async () => {
|
||||
page.state.baseMount = baseMount;
|
||||
page.state.secretMountType = secretMountType;
|
||||
await page.router.changePage(linkPage);
|
||||
}}
|
||||
>
|
||||
<a href={link}>
|
||||
{linkText}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
export class SecretsHomePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("HOME");
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
if (!(await prePageChecks(this.router))) return;
|
||||
type SecretsState = {
|
||||
mountsMap: Map<String, MountType>;
|
||||
capabilities: string[];
|
||||
}
|
||||
|
||||
this.state.baseMount = "";
|
||||
this.state.secretPath = [];
|
||||
this.state.secretItem = "";
|
||||
this.state.secretVersion = null;
|
||||
export class Secrets extends Component<DefaultPageProps, SecretsState> {
|
||||
async componentDidMount() {
|
||||
if (!(await prePageChecks(this.props.state))) return;
|
||||
|
||||
const mountsCapabilities = await getCapsPath("/sys/mounts");
|
||||
const mounts = await getMounts();
|
||||
// sort it by secretPath so it's in alphabetical order consistantly.
|
||||
const mountsMap = sortedObjectMap(mounts);
|
||||
this.setState({
|
||||
capabilities: mountsCapabilities,
|
||||
mountsMap: mountsMap as Map<String, MountType>
|
||||
})
|
||||
}
|
||||
|
||||
render(
|
||||
|
||||
render() {
|
||||
return this.state.mountsMap && (
|
||||
<>
|
||||
<PageTitle title={i18next.t("secrets_home_page_title")} />
|
||||
<div>
|
||||
<div>
|
||||
<p>
|
||||
{mountsCapabilities.includes("sudo") && mountsCapabilities.includes("create") && (
|
||||
{this.state.capabilities.includes("sudo") && this.state.capabilities.includes("create") && (
|
||||
<button
|
||||
class="uk-button uk-button-primary"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("NEW_SECRETS_ENGINE");
|
||||
onClick={() => {
|
||||
route("/secrets/new_secrets_engine")
|
||||
}}
|
||||
>
|
||||
{i18next.t("secrets_home_new_secrets_engine_button")}
|
||||
|
@ -98,21 +98,18 @@ export class SecretsHomePage extends Page {
|
|||
</div>
|
||||
<div class="uk-margin-top">
|
||||
<ul class="uk-nav uk-nav-default">
|
||||
{Array.from(mountsMap as Map<string, MountType>).map((args: [string, MountType]) => {
|
||||
{Array.from(this.state.mountsMap).map((args: [string, MountType]) => {
|
||||
const baseMount = args[0];
|
||||
const mount = args[1];
|
||||
console.log(baseMount, mount)
|
||||
if (isSupportedMount(mount)) {
|
||||
return <MountLink page={this} mount={mount} baseMount={baseMount} />;
|
||||
return <MountLink state={this.props.state} mount={mount} baseMount={baseMount} />;
|
||||
}
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>,
|
||||
this.router.pageContentElement,
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("secrets_home_page_title");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,46 +1,37 @@
|
|||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { deleteTOTP } from "../../../../api/totp/deleteTOTP";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { route } from "preact-router";
|
||||
|
||||
export class TOTPDeletePage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async cleanup(): Promise<void> {
|
||||
this.state.secretItem = "";
|
||||
}
|
||||
|
||||
async goBack(): Promise<void> {
|
||||
this.state.secretItem = "";
|
||||
await this.router.changePage("TOTP_VIEW");
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class TOTPDelete extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h5>{i18next.t("totp_delete_text")}</h5>
|
||||
<button
|
||||
class="uk-button uk-button-danger"
|
||||
onClick={async () => {
|
||||
await deleteTOTP(this.state.baseMount, this.state.secretItem);
|
||||
await this.goBack();
|
||||
let mount = this.props.matches["mount"];
|
||||
let item = this.props.matches["item"];
|
||||
await deleteTOTP(mount, item);
|
||||
route("/secrets/totp/list/" + mount)
|
||||
}}
|
||||
>
|
||||
{i18next.t("kv_delete_btn")}
|
||||
</button>
|
||||
</div>,
|
||||
this.router.pageContentElement,
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("totp_delete_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(
|
||||
// <SecretTitleElement page={this} suffix={i18next.t("totp_delete_suffix")} />,
|
||||
// this.router.pageTitleElement,
|
||||
// );
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("totp_delete_title");
|
||||
|
|
|
@ -8,6 +8,8 @@ import { SecretTitleElement } from "../SecretTitleElement";
|
|||
import { addNewTOTP } from "../../../../api/totp/addNewTOTP";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
import { route } from "preact-router";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
|
||||
function replaceAll(str: string, replace: string, replaceWith: string): string {
|
||||
return str.replace(new RegExp(replace, "g"), replaceWith);
|
||||
|
@ -19,7 +21,7 @@ function removeDashSpaces(str: string): string {
|
|||
return str;
|
||||
}
|
||||
|
||||
export class TOTPNewForm extends Component<{ page: Page }, { qrMode: boolean }> {
|
||||
export class TOTPNewForm extends Component<{ mount: string }, { qrMode: boolean }> {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
|
@ -30,7 +32,6 @@ export class TOTPNewForm extends Component<{ page: Page }, { qrMode: boolean }>
|
|||
uriInputRef = createRef<HTMLInputElement>();
|
||||
|
||||
async onSubmit(data: FormData): Promise<void> {
|
||||
const page = this.props.page;
|
||||
const parms = {
|
||||
url: data.get("uri") as string,
|
||||
key: removeDashSpaces(data.get("key") as string).toUpperCase(),
|
||||
|
@ -39,8 +40,8 @@ export class TOTPNewForm extends Component<{ page: Page }, { qrMode: boolean }>
|
|||
};
|
||||
|
||||
try {
|
||||
await addNewTOTP(page.state.baseMount, parms);
|
||||
await page.router.changePage("TOTP_VIEW");
|
||||
await addNewTOTP(this.props.mount, parms);
|
||||
route("/secrets/totp/list/" + this.props.mount)
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(`API Error: ${error.message}`);
|
||||
|
@ -118,24 +119,24 @@ export class TOTPNewForm extends Component<{ page: Page }, { qrMode: boolean }>
|
|||
}
|
||||
}
|
||||
|
||||
export class TOTPNewPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("TOTP_VIEW");
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(<TOTPNewForm page={this} />, this.router.pageContentElement);
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("totp_new_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
export class TOTPNew extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
let mount = this.props.matches["mount"];
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement type="totp" mount={mount} suffix={i18next.t("totp_new_suffix")} />
|
||||
<TOTPNewForm mount={this.props.matches["mount"]} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(
|
||||
// <SecretTitleElement page={this} suffix={i18next.t("totp_new_suffix")} />,
|
||||
// this.router.pageTitleElement,
|
||||
// );
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("totp_new_title");
|
||||
}
|
||||
|
|
|
@ -5,15 +5,21 @@ import { Grid, GridSizes } from "../../../elements/Grid";
|
|||
import { MarginInline } from "../../../elements/MarginInline";
|
||||
import { Page } from "../../../../types/Page";
|
||||
import { SecretTitleElement } from "../SecretTitleElement";
|
||||
import { getCapabilitiesPath, getCapsPath } from "../../../../api/sys/getCapabilities";
|
||||
import { CapabilitiesType, getCapabilitiesPath, getCapsPath } from "../../../../api/sys/getCapabilities";
|
||||
import { getTOTPCode } from "../../../../api/totp/getTOTPCode";
|
||||
import { getTOTPKeys } from "../../../../api/totp/getTOTPKeys";
|
||||
import { removeDoubleSlash } from "../../../../utils";
|
||||
import { setErrorText } from "../../../../pageUtils";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../../../types/DefaultPageProps";
|
||||
import { route } from "preact-router";
|
||||
|
||||
type TOTPGridItemProps = {
|
||||
mount: string; totpKey: string; canDelete: boolean;
|
||||
}
|
||||
|
||||
export class RefreshingTOTPGridItem extends Component<
|
||||
{ baseMount: string; totpKey: string; page: Page; canDelete: boolean },
|
||||
TOTPGridItemProps,
|
||||
{ totpValue: string }
|
||||
> {
|
||||
constructor() {
|
||||
|
@ -23,7 +29,7 @@ export class RefreshingTOTPGridItem extends Component<
|
|||
timer: unknown;
|
||||
|
||||
updateTOTPCode(): void {
|
||||
void getTOTPCode(this.props.baseMount, this.props.totpKey).then((code) => {
|
||||
void getTOTPCode(this.props.mount, this.props.totpKey).then((code) => {
|
||||
this.setState({ totpValue: code });
|
||||
});
|
||||
}
|
||||
|
@ -50,9 +56,7 @@ export class RefreshingTOTPGridItem extends Component<
|
|||
<button
|
||||
class="uk-button uk-button-danger"
|
||||
onClick={async () => {
|
||||
const page = this.props.page;
|
||||
page.state.secretItem = this.props.totpKey;
|
||||
await page.router.changePage("TOTP_DELETE");
|
||||
route("/secrets/totp/delete/" + this.props.mount + "/" + this.props.totpKey);
|
||||
}}
|
||||
>
|
||||
{i18next.t("totp_view_secret_delete_btn")}
|
||||
|
@ -65,34 +69,77 @@ export class RefreshingTOTPGridItem extends Component<
|
|||
}
|
||||
}
|
||||
|
||||
export class TOTPViewPage extends Page {
|
||||
type TOTPViewProps = DefaultPageProps & {
|
||||
}
|
||||
|
||||
type TOTPViewState = {
|
||||
capabilities?: CapabilitiesType;
|
||||
totpItems: TOTPGridItemProps[];
|
||||
}
|
||||
|
||||
export class TOTPView extends Component<TOTPViewProps, TOTPViewState> {
|
||||
constructor() {
|
||||
super();
|
||||
this.refresher = undefined;
|
||||
this.state = { capabilities: null, totpItems: [] };
|
||||
}
|
||||
|
||||
refresher: number;
|
||||
|
||||
async goBack(): Promise<void> {
|
||||
await this.router.changePage("SECRETS_HOME");
|
||||
async componentDidMount() {
|
||||
var mount = this.props.matches["mount"];
|
||||
const mountsPath = "/sys/mounts/" + mount;
|
||||
const caps = await getCapabilitiesPath([mountsPath, mount]);
|
||||
|
||||
let totpItems: TOTPGridItemProps[] = [];
|
||||
|
||||
// TODO: tidy this up i guess
|
||||
try {
|
||||
totpItems = await Promise.all(
|
||||
Array.from(await getTOTPKeys(mount)).map(async (key) => {
|
||||
const totpCaps = await getCapsPath(
|
||||
removeDoubleSlash(mount + "code/" + key),
|
||||
);
|
||||
if (totpCaps.includes("read")) {
|
||||
return {
|
||||
mount: mount,
|
||||
totpKey: key,
|
||||
canDelete: totpCaps.includes("delete"),
|
||||
};
|
||||
}
|
||||
}),
|
||||
);
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
if (error != DoesNotExistError) {
|
||||
setErrorText(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
this.state.secretItem = "";
|
||||
this.setState({
|
||||
capabilities: caps,
|
||||
totpItems: totpItems
|
||||
});
|
||||
}
|
||||
|
||||
const mountsPath = "/sys/mounts/" + this.state.baseMount;
|
||||
const caps = await getCapabilitiesPath([mountsPath, this.state.baseMount]);
|
||||
const mountCaps = caps[mountsPath];
|
||||
const totpCaps = caps[this.state.baseMount];
|
||||
render() {
|
||||
if (!this.state.capabilities) return;
|
||||
var mount = this.props.matches["mount"];
|
||||
|
||||
render(
|
||||
const mountsPath = "/sys/mounts/" + mount;
|
||||
const mountCaps = this.state.capabilities[mountsPath];
|
||||
const totpCaps = this.state.capabilities[mount];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SecretTitleElement type="totp" mount={mount} />
|
||||
<div>
|
||||
<p>
|
||||
{totpCaps.includes("create") && (
|
||||
<button
|
||||
class="uk-button uk-button-primary"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("TOTP_NEW");
|
||||
route("/secrets/totp/new/" + mount)
|
||||
}}
|
||||
>
|
||||
{i18next.t("totp_view_new_btn")}
|
||||
|
@ -102,7 +149,7 @@ export class TOTPViewPage extends Page {
|
|||
<button
|
||||
class="uk-button uk-button-danger"
|
||||
onClick={async () => {
|
||||
await this.router.changePage("DELETE_SECRET_ENGINE");
|
||||
route("/secrets/delete_engine/" + mount)
|
||||
}}
|
||||
>
|
||||
{i18next.t("totp_view_delete_btn")}
|
||||
|
@ -111,44 +158,25 @@ export class TOTPViewPage extends Page {
|
|||
</p>
|
||||
<div id="totpList">
|
||||
{
|
||||
await (async () => {
|
||||
try {
|
||||
const elem = await Promise.all(
|
||||
Array.from(await getTOTPKeys(this.state.baseMount)).map(async (key) => {
|
||||
const caps = await getCapsPath(
|
||||
removeDoubleSlash(this.state.baseMount + "code/" + key),
|
||||
);
|
||||
if (caps.includes("read")) {
|
||||
return (
|
||||
<RefreshingTOTPGridItem
|
||||
baseMount={this.state.baseMount}
|
||||
totpKey={key}
|
||||
page={this}
|
||||
canDelete={caps.includes("delete")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
return elem;
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
if (error == DoesNotExistError) {
|
||||
(() => {
|
||||
if (this.state.totpItems.length == 0) {
|
||||
return <p>{i18next.t("totp_view_empty")}</p>;
|
||||
} else {
|
||||
setErrorText(error.message);
|
||||
}
|
||||
return this.state.totpItems.map((totpItem) => {
|
||||
return <RefreshingTOTPGridItem
|
||||
mount={totpItem.mount}
|
||||
totpKey={totpItem.totpKey}
|
||||
canDelete={totpItem.canDelete}
|
||||
/>
|
||||
})
|
||||
}
|
||||
})()
|
||||
}
|
||||
</div>
|
||||
</div>,
|
||||
this.router.pageContentElement,
|
||||
);
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(<SecretTitleElement page={this} />, this.router.pageTitleElement);
|
||||
);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
|
|
|
@ -76,12 +76,12 @@ export class NewTransitKeyPage extends Page {
|
|||
}
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("transit_new_key_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(
|
||||
// <SecretTitleElement page={this} suffix={i18next.t("transit_new_key_suffix")} />,
|
||||
// this.router.pageTitleElement,
|
||||
// );
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("transit_new_key_title");
|
||||
|
|
|
@ -82,12 +82,12 @@ export class TransitDecryptPage extends Page {
|
|||
}
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("transit_decrypt_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(
|
||||
// <SecretTitleElement page={this} suffix={i18next.t("transit_decrypt_suffix")} />,
|
||||
// this.router.pageTitleElement,
|
||||
// );
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("transit_decrypt_title");
|
||||
|
|
|
@ -79,12 +79,12 @@ export class TransitEncryptPage extends Page {
|
|||
}
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("transit_encrypt_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(
|
||||
// <SecretTitleElement page={this} suffix={i18next.t("transit_encrypt_suffix")} />,
|
||||
// this.router.pageTitleElement,
|
||||
// );
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("transit_encrypt_title");
|
||||
|
|
|
@ -94,12 +94,12 @@ export class TransitRewrapPage extends Page {
|
|||
}
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(
|
||||
<SecretTitleElement page={this} suffix={i18next.t("transit_rewrap_suffix")} />,
|
||||
this.router.pageTitleElement,
|
||||
);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(
|
||||
// <SecretTitleElement page={this} suffix={i18next.t("transit_rewrap_suffix")} />,
|
||||
// this.router.pageTitleElement,
|
||||
// );
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("transit_rewrap_title");
|
||||
|
|
|
@ -116,9 +116,9 @@ export class TransitViewPage extends Page {
|
|||
);
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(<SecretTitleElement page={this} />, this.router.pageTitleElement);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(<SecretTitleElement page={this} />, this.router.pageTitleElement);
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("transit_view_title");
|
||||
|
|
|
@ -52,9 +52,9 @@ export class TransitViewSecretPage extends Page {
|
|||
);
|
||||
}
|
||||
|
||||
async renderPageTitle(): Promise<void> {
|
||||
render(<SecretTitleElement page={this} />, this.router.pageTitleElement);
|
||||
}
|
||||
//async renderPageTitle(): Promise<void> {
|
||||
// render(<SecretTitleElement page={this} />, this.router.pageTitleElement);
|
||||
//}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("transit_view_secret_title");
|
||||
|
|
|
@ -5,19 +5,22 @@ import translations from "../../translations/index.mjs";
|
|||
import { Form } from "../elements/Form";
|
||||
import { Margin } from "../elements/Margin";
|
||||
import { MarginInline } from "../elements/MarginInline";
|
||||
import { Page } from "../../types/Page";
|
||||
import { reloadNavBar } from "../elements/NavBar";
|
||||
import { render } from "preact";
|
||||
import { Component } from "preact";
|
||||
import i18next from "i18next";
|
||||
import { route } from "preact-router";
|
||||
import { PageTitle } from "../elements/PageTitle";
|
||||
import { DefaultPageProps } from "../../types/DefaultPageProps.js";
|
||||
|
||||
const languageIDs = Object.getOwnPropertyNames(translations);
|
||||
|
||||
export class SetLanguagePage extends Page {
|
||||
export class SetLanguage extends Component<DefaultPageProps> {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={i18next.t("set_language_title")} />
|
||||
<Form onSubmit={(data) => this.onSubmit(data)}>
|
||||
<Margin>
|
||||
<select class="uk-select uk-form-width-large" name="language">
|
||||
|
@ -34,22 +37,20 @@ export class SetLanguagePage extends Page {
|
|||
{i18next.t("set_language_btn")}
|
||||
</button>
|
||||
</MarginInline>
|
||||
</Form>,
|
||||
this.router.pageContentElement,
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
async onSubmit(data: FormData): Promise<void> {
|
||||
const language = data.get("language") as string;
|
||||
this.state.language = language;
|
||||
this.props.state.language = language;
|
||||
|
||||
const t = await i18next.changeLanguage(language);
|
||||
this.state.pageDirection = t("language_direction");
|
||||
reloadNavBar(this.router);
|
||||
await this.router.changePage("HOME");
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("set_language_title");
|
||||
this.props.state.pageDirection = t("language_direction");
|
||||
// TODO: make navbar somethingy
|
||||
//reloadNavBar(this.router);
|
||||
route("/");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import { Form } from "../elements/Form";
|
||||
import { Margin } from "../elements/Margin";
|
||||
import { Page } from "../../types/Page";
|
||||
import { render } from "preact";
|
||||
import { Component, render } from "preact";
|
||||
import { DefaultPageProps } from "../../types/DefaultPageProps";
|
||||
import { route } from "preact-router";
|
||||
import { PageTitle } from "../elements/PageTitle";
|
||||
|
||||
export class SetVaultURLPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
async render(): Promise<void> {
|
||||
render(
|
||||
export class SetVaultURL extends Component<DefaultPageProps> {
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={this.name} />
|
||||
<Form onSubmit={(data) => this.onSubmit(data)}>
|
||||
<Margin>
|
||||
<input
|
||||
|
@ -25,18 +27,19 @@ export class SetVaultURLPage extends Page {
|
|||
Set
|
||||
</button>
|
||||
</Margin>
|
||||
</Form>,
|
||||
|
||||
this.router.pageContentElement,
|
||||
</Form>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
async onSubmit(data: FormData): Promise<void> {
|
||||
this.state.apiURL = data.get("vaultURL") as string;
|
||||
await this.router.changePage("HOME");
|
||||
// TODO: check if vault is actually working here.
|
||||
this.props.state.apiURL = data.get("vaultURL") as string;
|
||||
route("/")
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
// TODO:
|
||||
return "Set Vault URL";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@ import { setErrorText } from "../../pageUtils";
|
|||
import { submitUnsealKey } from "../../api/sys/submitUnsealKey";
|
||||
import { toStr } from "../../utils";
|
||||
import i18next from "i18next";
|
||||
import { DefaultPageProps } from "../../types/DefaultPageProps";
|
||||
import { PageTitle } from "../elements/PageTitle";
|
||||
import { route } from "preact-router";
|
||||
|
||||
const UnsealInputModes = {
|
||||
FORM_INPUT: "FORM_INPUT",
|
||||
|
@ -50,7 +53,7 @@ type UnsealPageState = {
|
|||
keys_needed: number;
|
||||
};
|
||||
|
||||
export class UnsealPageElement extends Component<{ page: Page }, UnsealPageState> {
|
||||
export class Unseal extends Component<DefaultPageProps, UnsealPageState> {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
|
@ -79,7 +82,7 @@ export class UnsealPageElement extends Component<{ page: Page }, UnsealPageState
|
|||
keys_needed: data.t,
|
||||
});
|
||||
if (!data.sealed) {
|
||||
void this.props.page.router.changePage("HOME");
|
||||
route("/");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -97,6 +100,8 @@ export class UnsealPageElement extends Component<{ page: Page }, UnsealPageState
|
|||
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<PageTitle title={i18next.t("unseal_vault_text")} />
|
||||
<div>
|
||||
<progress
|
||||
class="uk-progress"
|
||||
|
@ -138,20 +143,7 @@ export class UnsealPageElement extends Component<{ page: Page }, UnsealPageState
|
|||
: i18next.t("unseal_qr_btn")}
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class UnsealPage extends Page {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(<UnsealPageElement page={this} />, this.router.pageContentElement);
|
||||
}
|
||||
|
||||
get name(): string {
|
||||
return i18next.t("unseal_vault_text");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ module.exports = {
|
|||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'bundle.js',
|
||||
publicPath: '/',
|
||||
},
|
||||
stats: {
|
||||
colors: true,
|
||||
|
@ -31,6 +32,7 @@ module.exports = {
|
|||
],
|
||||
devServer: {
|
||||
open: process.env.BROWSER,
|
||||
historyApiFallback: true,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['node_modules'],
|
||||
|
|
|
@ -41,6 +41,7 @@ module.exports = {
|
|||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'bundle.js',
|
||||
publicPath: '/',
|
||||
},
|
||||
stats: {
|
||||
colors: true,
|
||||
|
@ -56,6 +57,7 @@ module.exports = {
|
|||
],
|
||||
devServer: {
|
||||
open: process.env.BROWSER || "microsoft-edge-dev",
|
||||
historyApiFallback: true,
|
||||
},
|
||||
resolve: {
|
||||
modules: ['node_modules'],
|
||||
|
|
Loading…
Reference in a new issue