Lint code harder.
This commit is contained in:
parent
f4aa14f968
commit
a347939896
|
@ -1,18 +1,20 @@
|
|||
{
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:import/errors",
|
||||
"plugin:import/warnings",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"plugins": [
|
||||
"sort-imports-es6-autofix",
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:import/errors",
|
||||
"plugin:import/warnings",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:@typescript-eslint/recommended-requiring-type-checking"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 12,
|
||||
"sourceType": "module",
|
||||
"experimentalObjectRestSpread": true
|
||||
"experimentalObjectRestSpread": true,
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"globals": {
|
||||
"pageContent": "writable",
|
||||
|
|
|
@ -71,7 +71,7 @@ export class PageState {
|
|||
}
|
||||
|
||||
get currentSecretPath(): string[] {
|
||||
return JSON.parse(localStorage.getItem('currentSecretPath') || "[]");
|
||||
return JSON.parse(localStorage.getItem('currentSecretPath') || "[]") as string[];
|
||||
}
|
||||
set currentSecretPath(value: string[]) {
|
||||
localStorage.setItem('currentSecretPath', JSON.stringify(value));
|
||||
|
@ -104,14 +104,14 @@ export class PageState {
|
|||
}
|
||||
get currentPage(): Page | string {
|
||||
const curPage = localStorage.getItem('currentPage') || "HOME";
|
||||
return (allPages as any)[curPage];
|
||||
return allPages[curPage];
|
||||
}
|
||||
set currentPage(value: Page | string) {
|
||||
if (typeof value == 'object') {
|
||||
const key = getKeyByObjectPropertyValue(allPages, value);
|
||||
localStorage.setItem('currentPage', key);
|
||||
} else {
|
||||
localStorage.setItem('currentPage', (value as string));
|
||||
localStorage.setItem('currentPage', value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import { pageState } from "../globalPageState";
|
||||
|
||||
export function getHeaders(): any {
|
||||
export function getHeaders(): Record<string, string> {
|
||||
return {
|
||||
"X-Vault-Token": pageState.token,
|
||||
}
|
||||
|
|
|
@ -8,13 +8,12 @@ export async function usernameLogin(username: string, password: string): Promise
|
|||
},
|
||||
body: JSON.stringify({ "username": username, "password": password })
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
if ("auth" in data) {
|
||||
return data.auth.client_token;
|
||||
} else if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
});
|
||||
|
||||
const resp = await fetch(request);
|
||||
const data = await resp.json() as { auth?: { client_token: string }; errors?: string[] };
|
||||
if ("auth" in data) {
|
||||
return data.auth.client_token;
|
||||
} else if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export async function createOrUpdateSecret(
|
|||
});
|
||||
const response = await fetch(request);
|
||||
if (!response.ok) {
|
||||
const json = await response.json();
|
||||
const json = await response.json() as {errors: string[]};
|
||||
throw new Error(json.errors[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,12 +32,12 @@ export async function deleteSecret(
|
|||
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
|
||||
request = new Request(appendAPIURL(secretURL), {
|
||||
method: "DELETE",
|
||||
headers: (getHeaders() as any),
|
||||
headers: getHeaders(),
|
||||
});
|
||||
}
|
||||
const response = await fetch(request);
|
||||
if (!response.ok) {
|
||||
const json = await response.json();
|
||||
const json = await response.json() as {errors: string[]};
|
||||
throw new Error(json.errors[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ export async function getSecret(
|
|||
secretPath: string[],
|
||||
name: string,
|
||||
version: string|null = null
|
||||
): Promise<Record<any, any>> {
|
||||
): Promise<Record<string, unknown>> {
|
||||
let secretURL = "";
|
||||
if (mountType == "kv-v2") {
|
||||
secretURL = `/v1/${baseMount}/data/${secretPath.join("")}/${name}`;
|
||||
|
@ -16,12 +16,14 @@ export async function getSecret(
|
|||
secretURL = `/v1/${baseMount}/${secretPath.join("")}/${name}`;
|
||||
}
|
||||
const request = new Request(appendAPIURL(secretURL), {
|
||||
headers: (getHeaders() as any),
|
||||
headers: getHeaders(),
|
||||
});
|
||||
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return mountType == "kv-v2" ? data.data.data : data.data;
|
||||
});
|
||||
const resp = await fetch(request);
|
||||
const data = await resp.json() as unknown;
|
||||
if (mountType == "kv-v2") {
|
||||
return (data as {data: {data: Record<string, unknown>}}).data.data;
|
||||
} else {
|
||||
return (data as {data: Record<string, unknown>}).data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
|
||||
type SecretMetadataType = {
|
||||
versions: Record<string, Record<any, any>>
|
||||
versions: Record<string, unknown>
|
||||
}
|
||||
|
||||
export async function getSecretMetadata(
|
||||
|
@ -10,12 +10,10 @@ export async function getSecretMetadata(
|
|||
name: string
|
||||
): Promise<SecretMetadataType> {
|
||||
const request = new Request(appendAPIURL(`/v1/${baseMount}/metadata/${secretPath.join("")}/${name}`), {
|
||||
headers: (getHeaders() as any),
|
||||
headers: getHeaders(),
|
||||
});
|
||||
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data.data;
|
||||
});
|
||||
const resp = await fetch(request);
|
||||
const data = await resp.json() as {data: SecretMetadataType};
|
||||
return data.data;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ import { DoesNotExistError } from "../../types/internalErrors";
|
|||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
|
||||
export async function getSecrets(
|
||||
baseMount: string,
|
||||
mountType: string,
|
||||
baseMount: string,
|
||||
mountType: string,
|
||||
secretPath: string[]
|
||||
): Promise<string[]> {
|
||||
let secretURL = "";
|
||||
|
@ -14,14 +14,12 @@ export async function getSecrets(
|
|||
secretURL = `/v1/${baseMount}/${secretPath.join("")}?list=true`;
|
||||
}
|
||||
const request = new Request(appendAPIURL(secretURL), {
|
||||
headers: (getHeaders() as any),
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
if (response.status == 404) {
|
||||
throw DoesNotExistError;
|
||||
}
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data.data.keys;
|
||||
headers: getHeaders(),
|
||||
});
|
||||
const resp = await fetch(request);
|
||||
if (resp.status == 404) {
|
||||
throw DoesNotExistError;
|
||||
}
|
||||
const data = await resp.json() as { data: { keys: string[] } };
|
||||
return data.data.keys;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ export async function undeleteSecret(
|
|||
});
|
||||
const response = await fetch(request);
|
||||
if (!response.ok) {
|
||||
const json = await response.json();
|
||||
const json = await response.json() as {errors: string[]};
|
||||
throw new Error(json.errors[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,9 @@ export async function getCapabilitiesPath(path: string): Promise<string[]> {
|
|||
}
|
||||
)
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data.capabilities;
|
||||
});
|
||||
const response = await fetch(request);
|
||||
const data = await response.json() as {capabilities: string[]};
|
||||
return data.capabilities;
|
||||
}
|
||||
|
||||
export async function getCapabilities(
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
|
||||
type MountsType = {
|
||||
[key: string]: {
|
||||
export type MountType = {
|
||||
type: string
|
||||
options: {
|
||||
version: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type MountsType = {
|
||||
[key: string]: MountType;
|
||||
}
|
||||
|
||||
export async function getMounts(): Promise<MountsType> {
|
||||
const request = new Request(appendAPIURL("/v1/sys/internal/ui/mounts"), {
|
||||
headers: (getHeaders() as any),
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data.data.secret;
|
||||
headers: getHeaders(),
|
||||
});
|
||||
const resp = await fetch(request);
|
||||
const data = await resp.json() as {data: {secret: MountsType}};
|
||||
return data.data.secret;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,7 @@ export type SealStatusType = {
|
|||
|
||||
export async function getSealStatus(): Promise<SealStatusType> {
|
||||
const request = new Request(appendAPIURL("/v1/sys/seal-status"));
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data;
|
||||
});
|
||||
const resp = await fetch(request)
|
||||
const data = await resp.json() as SealStatusType;
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
import { TokenInfo } from "../types/token";
|
||||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
|
||||
export async function lookupSelf(): Promise<TokenInfo> {
|
||||
const request = new Request(appendAPIURL("/v1/auth/token/lookup-self"), {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
if ("data" in data) {
|
||||
return data.data;
|
||||
} else if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
});
|
||||
const resp = await fetch(request);
|
||||
const data = await resp.json() as { data?: TokenInfo; errors?: string[] };
|
||||
if ("data" in data) {
|
||||
return data.data;
|
||||
} else if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,9 @@ export async function renewSelf(): Promise<void> {
|
|||
},
|
||||
body: JSON.stringify({})
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
});
|
||||
const resp = await fetch(request)
|
||||
const data = await resp.json() as { errors?: string[] };
|
||||
if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,9 @@ export async function sealVault(): Promise<void> {
|
|||
method: 'PUT',
|
||||
headers: getHeaders(),
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
});
|
||||
const resp = await fetch(request)
|
||||
const data = await resp.json() as { errors?: string[] };
|
||||
if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ export async function submitUnsealKey(key: string): Promise<void> {
|
|||
"key": key
|
||||
})
|
||||
});
|
||||
const response = await fetch(request);
|
||||
if (!response.ok) {
|
||||
const json = await response.json();
|
||||
throw new Error(json.errors[0]);
|
||||
const resp = await fetch(request)
|
||||
if (!resp.ok) {
|
||||
const data = await resp.json() as { errors?: string[] };
|
||||
if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
import { removeDoubleSlash } from "../../utils";
|
||||
|
||||
|
||||
export async function addNewTOTP(baseMount: string, parms: {name: string}): Promise<void> {
|
||||
const request = new Request(appendAPIURL(removeDoubleSlash(`/v1/${baseMount}/keys/${parms.name}`)), {
|
||||
method: 'POST',
|
||||
|
@ -11,9 +10,11 @@ export async function addNewTOTP(baseMount: string, parms: {name: string}): Prom
|
|||
},
|
||||
body: JSON.stringify(parms)
|
||||
});
|
||||
const response = await fetch(request);
|
||||
if (!response.ok) {
|
||||
const json = await response.json();
|
||||
throw new Error(json.errors[0]);
|
||||
const resp = await fetch(request)
|
||||
if (!resp.ok) {
|
||||
const data = await resp.json() as { errors?: string[] };
|
||||
if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,7 @@ export async function getTOTPCode(baseMount: string, name: string): Promise<stri
|
|||
new Request(appendAPIURL(`/v1/${baseMount}/code/${name}`), {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data.data.code;
|
||||
});
|
||||
const resp = await fetch(request)
|
||||
const data = await resp.json() as {data: {code: string}};
|
||||
return data.data.code;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,15 @@
|
|||
import { DoesNotExistError } from "../../types/internalErrors";
|
||||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
|
||||
|
||||
export async function getTOTPKeys(baseMount: string): Promise<string[]> {
|
||||
const request = new Request(appendAPIURL(`/v1/${baseMount}/keys?list=true`), {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
if (response.status == 404) {
|
||||
throw DoesNotExistError;
|
||||
}
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data.data.keys;
|
||||
});
|
||||
|
||||
const resp = await fetch(request);
|
||||
if (resp.status == 404) {
|
||||
throw DoesNotExistError;
|
||||
}
|
||||
const data = await resp.json() as {data: {keys: string[] }};
|
||||
return data.data.keys;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import { DoesNotExistError } from "../../types/internalErrors";
|
||||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
import { TransitKeyType } from "../types/transit";
|
||||
import { appendAPIURL, getHeaders } from "../apiUtils";
|
||||
|
||||
export async function getTransitKey(baseMount: string, name: string): Promise<TransitKeyType> {
|
||||
const request = new Request(appendAPIURL(`/v1/${baseMount}/keys/${name}`), {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
if (response.status == 404) {
|
||||
throw DoesNotExistError;
|
||||
}
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data.data;
|
||||
});
|
||||
|
||||
const resp = await fetch(request);
|
||||
if (resp.status == 404) {
|
||||
throw DoesNotExistError;
|
||||
}
|
||||
const data = await resp.json() as { data: TransitKeyType };
|
||||
return data.data;
|
||||
}
|
||||
|
|
|
@ -5,12 +5,10 @@ export async function getTransitKeys(baseMount: string): Promise<string[]> {
|
|||
const request = new Request(appendAPIURL(`/v1/${baseMount}/keys?list=true`), {
|
||||
headers: getHeaders(),
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
if (response.status == 404) {
|
||||
throw DoesNotExistError;
|
||||
}
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
return data.data.keys;
|
||||
});
|
||||
const resp = await fetch(request);
|
||||
if (resp.status == 404) {
|
||||
throw DoesNotExistError;
|
||||
}
|
||||
const data = await resp.json() as { data: string[] };
|
||||
return data.data;
|
||||
}
|
||||
|
|
|
@ -22,12 +22,12 @@ export async function transitDecrypt(
|
|||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
const response = await fetch(request);
|
||||
const data = await response.json() as { errors?: string[]; data?: DecryptionResult; };
|
||||
if (!response.ok) {
|
||||
const json = await response.json();
|
||||
throw new Error(json.errors[0]);
|
||||
throw new Error(data.errors[0]);
|
||||
} else {
|
||||
const json = await response.json();
|
||||
return json.data;
|
||||
return data.data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,12 +22,12 @@ export async function transitEncrypt(
|
|||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
const response = await fetch(request);
|
||||
const data = await response.json() as { errors?: string[]; data?: EncryptionResult; };
|
||||
if (!response.ok) {
|
||||
const json = await response.json();
|
||||
throw new Error(json.errors[0]);
|
||||
throw new Error(data.errors[0]);
|
||||
} else {
|
||||
const json = await response.json();
|
||||
return json.data;
|
||||
return data.data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ export async function transitRewrap(
|
|||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
const response = await fetch(request);
|
||||
const data = await response.json() as { errors?: string[]; data?: RewrapResult; };
|
||||
if (!response.ok) {
|
||||
const json = await response.json();
|
||||
throw new Error(json.errors[0]);
|
||||
throw new Error(data.errors[0]);
|
||||
} else {
|
||||
const json = await response.json();
|
||||
return json.data;
|
||||
return data.data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ export type TokenInfo = {
|
|||
id: string;
|
||||
identity_policies: string[];
|
||||
issue_time: string;
|
||||
meta: any;
|
||||
meta: Record<string, string>;
|
||||
num_uses: number;
|
||||
orphan: Boolean;
|
||||
orphan: boolean;
|
||||
path: string;
|
||||
policies: string[];
|
||||
renewable: Boolean;
|
||||
renewable: boolean;
|
||||
ttl: number;
|
||||
}
|
|
@ -14,10 +14,10 @@ export const enum TransitKeyTypes {
|
|||
// Type when used to make new transit keys.
|
||||
export type TransitKeyBaseType = {
|
||||
name: string;
|
||||
convergent_encryption: Boolean;
|
||||
derived: Boolean;
|
||||
exportable: Boolean;
|
||||
allow_plaintext_backup: Boolean;
|
||||
convergent_encryption: boolean;
|
||||
derived: boolean;
|
||||
exportable: boolean;
|
||||
allow_plaintext_backup: boolean;
|
||||
type: keyof typeof TransitKeyTypes;
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,8 @@ export type TransitKeyType = TransitKeyBaseType & {
|
|||
};
|
||||
min_decryption_version: number;
|
||||
min_encryption_version: number;
|
||||
supports_encryption: Boolean;
|
||||
supports_decryption: Boolean;
|
||||
supports_derivation: Boolean;
|
||||
supports_signing: Boolean;
|
||||
supports_encryption: boolean;
|
||||
supports_decryption: boolean;
|
||||
supports_derivation: boolean;
|
||||
supports_signing: boolean;
|
||||
}
|
|
@ -10,7 +10,7 @@ export interface CopyableInputBoxType extends HTMLElement {
|
|||
|
||||
export function CopyableInputBox(text: string, copyable = true): CopyableInputBoxType {
|
||||
const inputBoxDiv = (makeElement({ tag: "div" }) as CopyableInputBoxType);
|
||||
let inputBoxCopyButton = null;
|
||||
let inputBoxCopyButton: HTMLElement = null;
|
||||
if (copyable) {
|
||||
inputBoxCopyButton = makeElement({
|
||||
tag: "a",
|
||||
|
@ -30,8 +30,8 @@ export function CopyableInputBox(text: string, copyable = true): CopyableInputBo
|
|||
const inputBoxInput = makeElement({
|
||||
tag: "input",
|
||||
class: ["uk-input", "uk-input-copyable"],
|
||||
attributes: { "readonly": true, "type": "text" },
|
||||
});
|
||||
attributes: { "readonly": "true", "type": "text" },
|
||||
}) as HTMLInputElement;
|
||||
|
||||
const inputBoxInner = MarginInline([
|
||||
inputBoxCopyButton,
|
||||
|
@ -40,7 +40,7 @@ export function CopyableInputBox(text: string, copyable = true): CopyableInputBo
|
|||
inputBoxDiv.appendChild(inputBoxInner);
|
||||
|
||||
inputBoxDiv.setText = function (text) {
|
||||
(inputBoxInput as HTMLInputElement).value = `${text}`;
|
||||
inputBoxInput.value = `${text}`;
|
||||
if (copyable) {
|
||||
inputBoxCopyButton.dataset.clipboardText = `${text}`;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,19 @@ import { addClipboardNotifications } from "../pageUtils";
|
|||
import { makeElement } from "../htmlUtils";
|
||||
import ClipboardJS from "clipboard";
|
||||
import FileSaver from 'file-saver';
|
||||
import UIkit from 'uikit/dist/js/uikit.min.js';
|
||||
import i18next from 'i18next';
|
||||
|
||||
export function CopyableModal(name: string, contentString: string): Element {
|
||||
return makeElement({
|
||||
type FileSaverType = {
|
||||
saveAs: (blob: Blob, name: string) => void;
|
||||
}
|
||||
|
||||
type ModalType = HTMLElement & {
|
||||
show: () => void;
|
||||
}
|
||||
|
||||
export function CopyableModal(name: string, contentString: string): ModalType {
|
||||
const modal = makeElement({
|
||||
tag: "div",
|
||||
class: "modal-sections",
|
||||
attributes: {
|
||||
|
@ -53,9 +62,9 @@ export function CopyableModal(name: string, contentString: string): Element {
|
|||
"data-clipboard-text": contentString
|
||||
},
|
||||
text: i18next.t("copy_modal_download_btn"),
|
||||
onclick: _ => {
|
||||
const blob = new Blob([contentString], {type: "text/plain;charset=utf-8"});
|
||||
FileSaver.saveAs(blob, "result.txt");
|
||||
onclick: () => {
|
||||
const blob = new Blob([contentString], { type: "text/plain;charset=utf-8" });
|
||||
(FileSaver as FileSaverType).saveAs(blob, "result.txt");
|
||||
}
|
||||
}),
|
||||
makeElement({
|
||||
|
@ -82,5 +91,9 @@ export function CopyableModal(name: string, contentString: string): Element {
|
|||
}),
|
||||
]
|
||||
})
|
||||
});
|
||||
}) as ModalType;
|
||||
modal.show = () => {
|
||||
(UIkit as { modal: (ModalType) => { show: () => void } }).modal(modal).show();
|
||||
}
|
||||
return modal;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ export async function QRScanner(onScan: (code: string) => void): Promise<QRScann
|
|||
if (lastSeenValue == value) return;
|
||||
onScan(value);
|
||||
});
|
||||
qrScanner.start();
|
||||
void qrScanner.start();
|
||||
|
||||
QRInput.deinit = () => {
|
||||
try {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { makeElement } from "../htmlUtils";
|
||||
|
||||
type TileParams = {
|
||||
condition: Boolean;
|
||||
condition: boolean;
|
||||
title: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
import { appendAPIURL, getHeaders } from "../api/apiUtils";
|
||||
|
||||
export async function renewSelf(): Promise<void> {
|
||||
const request = new Request(appendAPIURL("/v1/auth/token/renew-self"), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...getHeaders(),
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({})
|
||||
});
|
||||
return fetch(request).then(response => {
|
||||
return response.json();
|
||||
}).then(data => {
|
||||
if ("errors" in data) {
|
||||
throw new Error(data.errors[0]);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -2,7 +2,7 @@ import { de, enGB, fr, it, nl, ru } from 'date-fns/locale'
|
|||
import { formatDistance as formatDistanceReal} from 'date-fns';
|
||||
import { pageState } from "./globalPageState";
|
||||
|
||||
function getLocale(): any {
|
||||
function getLocale(): Locale {
|
||||
return {
|
||||
"en": enGB,
|
||||
"fr": fr,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { getObjectKeys } from "./utils";
|
||||
|
||||
type optionsFunctionsObject = {
|
||||
[key: string]: (e: any, arg: any) => void
|
||||
[key: string]: (e: Element, arg: unknown) => void
|
||||
}
|
||||
|
||||
const optionsFunctions: optionsFunctionsObject = {
|
||||
|
@ -13,9 +13,9 @@ const optionsFunctions: optionsFunctionsObject = {
|
|||
},
|
||||
"id": (e: Element, arg: string) => e.id = arg,
|
||||
"html": (e: Element, arg: string) => e.innerHTML = arg,
|
||||
"onclick": (e: HTMLButtonElement, arg: any) => e.onclick = arg,
|
||||
"onclick": (e: Element, arg: () => void) => (e as HTMLButtonElement).onclick = arg,
|
||||
"attributes": setElementAttributes,
|
||||
"text": (e: HTMLParagraphElement, arg: string) => e.innerText = arg,
|
||||
"text": (e: Element, arg: string) => (e as HTMLParagraphElement).innerText = arg,
|
||||
"children": (e: Element, arg: Element | Element[]) => {
|
||||
if (Array.isArray(arg)) {
|
||||
arg.forEach(child => {
|
||||
|
@ -34,13 +34,12 @@ interface ElementInfo {
|
|||
class?: string | string[];
|
||||
id?: string;
|
||||
html?: string;
|
||||
attributes?: {
|
||||
[propName: string]: any
|
||||
};
|
||||
attributes?: Record<string, string>;
|
||||
children?: Element | Element[];
|
||||
text?: string;
|
||||
thenRun?: (e: Element) => void;
|
||||
[propName: string]: any;
|
||||
onclick?: () => void;
|
||||
[propName: string]: unknown;
|
||||
}
|
||||
|
||||
export function makeElement(elementInfo: ElementInfo): HTMLElement {
|
||||
|
@ -49,14 +48,14 @@ export function makeElement(elementInfo: ElementInfo): HTMLElement {
|
|||
|
||||
for (const key of Object.getOwnPropertyNames(elementInfo)) {
|
||||
if (getObjectKeys(optionsFunctions).includes(key)) {
|
||||
(optionsFunctions as any)[key](element, elementInfo[key]);
|
||||
optionsFunctions[key](element, elementInfo[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
export function setElementAttributes(element: Element, attributes: { [propName: string]: any }): void {
|
||||
export function setElementAttributes(element: Element, attributes: Record<string, string>): void {
|
||||
for (const key of Object.getOwnPropertyNames(attributes)) {
|
||||
element.setAttribute(key, attributes[key]);
|
||||
}
|
||||
|
|
50
src/main.ts
50
src/main.ts
|
@ -2,14 +2,16 @@
|
|||
|
||||
// JS & CSS
|
||||
|
||||
/* eslint-disable */
|
||||
import "./scss/main.scss";
|
||||
import Icons from 'uikit/dist/js/uikit-icons.min.js';
|
||||
import UIkit from 'uikit/dist/js/uikit.min.js';
|
||||
// @ts-ignore
|
||||
UIkit.use(Icons);
|
||||
|
||||
/* eslint-disable */
|
||||
import Prism from "prismjs";
|
||||
import "prismjs/components/prism-json";
|
||||
// @ts-ignore
|
||||
Prism.highlightAll();
|
||||
/* eslint-enable */
|
||||
|
||||
|
@ -29,14 +31,19 @@ import i18next from 'i18next';
|
|||
// @ts-ignore
|
||||
import translations from './translations/index.mjs'
|
||||
|
||||
function ListItem(children) {
|
||||
function ListItem(children: Element[] | Element): HTMLElement {
|
||||
return makeElement({
|
||||
tag: "li",
|
||||
children: children
|
||||
});
|
||||
}
|
||||
|
||||
async function onLoad() {
|
||||
declare global {
|
||||
interface Window { pageContent: Element; }
|
||||
}
|
||||
|
||||
|
||||
function onLoad(): void {
|
||||
document.body.innerHTML = "";
|
||||
document.body.appendChild(makeElement({
|
||||
tag: "nav",
|
||||
|
@ -52,17 +59,17 @@ async function onLoad() {
|
|||
ListItem(makeElement({
|
||||
tag: "a",
|
||||
text: i18next.t("home_btn"),
|
||||
onclick: _ => { changePage("HOME"); }
|
||||
onclick: () => { changePage("HOME"); }
|
||||
})),
|
||||
ListItem(makeElement({
|
||||
tag: "a",
|
||||
text: i18next.t("back_btn"),
|
||||
onclick: _ => { (pageState.currentPage as Page).goBack(); }
|
||||
onclick: () => { (pageState.currentPage as Page).goBack(); }
|
||||
})),
|
||||
ListItem(makeElement({
|
||||
tag: "a",
|
||||
text: i18next.t("refresh_btn"),
|
||||
onclick: _ => { changePage(pageState.currentPageString); }
|
||||
onclick: () => { changePage(pageState.currentPageString); }
|
||||
})),
|
||||
]
|
||||
})
|
||||
|
@ -77,7 +84,7 @@ async function onLoad() {
|
|||
ListItem(makeElement({
|
||||
tag: "a",
|
||||
text: i18next.t("me_btn"),
|
||||
onclick: _ => { changePage("ME"); }
|
||||
onclick: () => { changePage("ME"); }
|
||||
}))
|
||||
]
|
||||
})
|
||||
|
@ -105,43 +112,44 @@ async function onLoad() {
|
|||
})
|
||||
}));
|
||||
|
||||
(window as any).pageContent = document.querySelector("#pageContent");
|
||||
window.pageContent = document.querySelector("#pageContent");
|
||||
|
||||
if (process.env.NODE_ENV == "development") {
|
||||
await playground();
|
||||
playground();
|
||||
}
|
||||
|
||||
renderPage();
|
||||
|
||||
setInterval(async () => {
|
||||
setInterval(() => {
|
||||
if (pageState.currentPageString != "UNSEAL") {
|
||||
if (pageState.apiURL.length != 0) { return; }
|
||||
const sealStatus = await getSealStatus();
|
||||
if (sealStatus.sealed) {
|
||||
changePage("UNSEAL");
|
||||
return;
|
||||
}
|
||||
void getSealStatus().then((sealStatus) => {
|
||||
if (sealStatus.sealed) {
|
||||
changePage("UNSEAL");
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async function () {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
console.log("Loading...");
|
||||
// @ts-expect-error
|
||||
console.log("Build Data:", BUILD_STRING);
|
||||
i18next.init({
|
||||
void i18next.init({
|
||||
lng: pageState.language,
|
||||
fallbackLng: 'en',
|
||||
debug: true,
|
||||
// @ts-ignore
|
||||
resources: Object.fromEntries(Object.entries(translations).map(([k, v]) => [k, { translation: v }])),
|
||||
interpolation: {
|
||||
format: function (value, format, _) {
|
||||
format: function (value: unknown, format, _): string {
|
||||
if (format === 'until_date' && value instanceof Date) return formatDistance(new Date(), new Date(value));
|
||||
return value;
|
||||
return value as string;
|
||||
}
|
||||
}
|
||||
}).then(async function (_) {
|
||||
await onLoad();
|
||||
}).then(function (_) {
|
||||
onLoad();
|
||||
});
|
||||
}, false);
|
||||
|
|
|
@ -46,13 +46,13 @@ export async function prePageChecks(): Promise<boolean> {
|
|||
|
||||
export function addClipboardNotifications(clipboard: ClipboardJS, timeout = 1000): void {
|
||||
clipboard.on('success', () => {
|
||||
(UIkit as any).notification(i18next.t("notification_copy_success"), {
|
||||
(UIkit as {notification: (title: unknown, options: unknown) => void}).notification(i18next.t("notification_copy_success"), {
|
||||
status: 'success',
|
||||
timeout: timeout
|
||||
});
|
||||
});
|
||||
clipboard.on('error', function (e: Error) {
|
||||
(UIkit as any).notification(i18next.t("notification_copy_error", {
|
||||
(UIkit as {notification: (title: unknown, options: unknown) => void}).notification(i18next.t("notification_copy_error", {
|
||||
"error": e.message
|
||||
}), {
|
||||
status: 'danger',
|
||||
|
@ -64,9 +64,9 @@ export function addClipboardNotifications(clipboard: ClipboardJS, timeout = 1000
|
|||
export function setErrorText(text: string): void {
|
||||
const errorTextElement = document.querySelector("#errorText");
|
||||
if (errorTextElement) {
|
||||
(document.querySelector("#errorText") as HTMLElement).innerText = `Error: ${text}`;
|
||||
(document.querySelector("#errorText") as HTMLParagraphElement).innerText = `Error: ${text}`;
|
||||
}
|
||||
(UIkit as any).notification({
|
||||
(UIkit as {notification: (options: unknown) => void}).notification({
|
||||
message: `Error: ${text}`,
|
||||
status: 'danger',
|
||||
pos: 'top-center',
|
||||
|
@ -87,13 +87,13 @@ export function changePage(page: string, shouldSwitch = true): void {
|
|||
export function renderPage(): void {
|
||||
document.documentElement.dir = pageState.pageDirection;
|
||||
console.log("Rendering Page: ", (pageState.currentPage as Page).name);
|
||||
(document.querySelector("#pageContent") as HTMLElement).innerHTML = "";
|
||||
(document.querySelector("#pageContent") ).innerHTML = "";
|
||||
setPageTitle((pageState.currentPage as Page).name);
|
||||
(pageState.currentPage as Page).render();
|
||||
}
|
||||
|
||||
export function setPageTitle(title: string | HTMLElement): void {
|
||||
const pageTitle = (document.getElementById("pageTitle") as HTMLElement);
|
||||
const pageTitle = (document.getElementById("pageTitle") );
|
||||
pageTitle.innerHTML = "";
|
||||
if (typeof title === "string") {
|
||||
pageTitle.innerText = title.toString();
|
||||
|
@ -154,7 +154,7 @@ export function setTitleElement(pageState: PageState): void {
|
|||
}
|
||||
|
||||
export function setPageContent(content: string | HTMLElement): void {
|
||||
const pageContent = (document.getElementById("pageContent") as HTMLElement);
|
||||
const pageContent = (document.getElementById("pageContent") );
|
||||
if (typeof content === "string") {
|
||||
pageContent.innerHTML = content;
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { MountType, getMounts } from "../api/sys/getMounts";
|
||||
import { Page } from "../types/Page";
|
||||
import { changePage, prePageChecks, setErrorText, setPageContent } from "../pageUtils";
|
||||
import { getMounts } from "../api/sys/getMounts";
|
||||
import { lookupSelf } from "../api/sys/lookupSelf";
|
||||
import { makeElement } from "../htmlUtils";
|
||||
import { pageState } from "../globalPageState";
|
||||
|
@ -48,9 +48,10 @@ export class HomePage extends Page {
|
|||
tag: "li",
|
||||
text: i18next.t("your_token_expires_in", {"date": new Date(selfTokenInfo.expire_time)})
|
||||
}));
|
||||
} catch (e) {
|
||||
setErrorText(e.message);
|
||||
if (e.message == "permission denied") {
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(error.message);
|
||||
if (error.message == "permission denied") {
|
||||
pageState.token = "";
|
||||
changePage("LOGIN");
|
||||
}
|
||||
|
@ -68,7 +69,7 @@ export class HomePage extends Page {
|
|||
// sort it by secretPath so it's in alphabetical order consistantly.
|
||||
const mountsMap = sortedObjectMap(mounts);
|
||||
|
||||
mountsMap.forEach(function (mount, baseMount) {
|
||||
mountsMap.forEach(function (mount: MountType, baseMount) {
|
||||
if (typeof mount != 'object') return;
|
||||
if (mount == null) return;
|
||||
if (!("type" in mount)) return;
|
||||
|
@ -97,7 +98,7 @@ export class HomePage extends Page {
|
|||
children: makeElement({
|
||||
tag: "a",
|
||||
text: linkText,
|
||||
onclick: _ => {
|
||||
onclick: () => {
|
||||
pageState.currentBaseMount = baseMount;
|
||||
pageState.currentMountType = mountType;
|
||||
changePage(linkPage);
|
||||
|
|
|
@ -31,8 +31,8 @@ export class KeyValueDeletePage extends Page {
|
|||
tag: "button",
|
||||
class: ["uk-button", "uk-button-danger"],
|
||||
text: i18next.t("kv_delete_btn"),
|
||||
onclick: _ => {
|
||||
deleteSecret(
|
||||
onclick: () => {
|
||||
void deleteSecret(
|
||||
pageState.currentBaseMount,
|
||||
pageState.currentMountType,
|
||||
pageState.currentSecretPath,
|
||||
|
|
|
@ -29,7 +29,7 @@ export class KeyValueNewPage extends Page {
|
|||
tag: "input",
|
||||
class: ["uk-input", "uk-form-width-medium"],
|
||||
attributes: {
|
||||
required: true,
|
||||
required: "true",
|
||||
type: "text",
|
||||
placeholder: i18next.t("kv_new_path"),
|
||||
name: "path"
|
||||
|
@ -53,9 +53,9 @@ export class KeyValueNewPage extends Page {
|
|||
}) as HTMLFormElement;
|
||||
setPageContent(this.addKVNewForm);
|
||||
|
||||
this.addKVNewForm.addEventListener("submit", function (e) {
|
||||
this.addKVNewForm.addEventListener("submit", function (e: Event) {
|
||||
e.preventDefault();
|
||||
this.newKVSecretHandleForm();
|
||||
(this as KeyValueNewPage).newKVSecretHandleForm();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ export class KeyValueNewPage extends Page {
|
|||
).then(_ => {
|
||||
changePage("KEY_VALUE_VIEW");
|
||||
return;
|
||||
}).catch(e => {
|
||||
}).catch((e: Error) => {
|
||||
setErrorText(e.message);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ export class KeyValueSecretPage extends Page {
|
|||
tag: "button",
|
||||
id: "deleteButton",
|
||||
class: ["uk-button", "uk-button-danger"],
|
||||
onclick: _ => { changePage("KEY_VALUE_DELETE"); },
|
||||
onclick: () => { changePage("KEY_VALUE_DELETE"); },
|
||||
text: deleteButtonText
|
||||
}));
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ export class KeyValueSecretPage extends Page {
|
|||
tag: "button",
|
||||
id: "editButton",
|
||||
class: ["uk-button", "uk-margin", "uk-button-primary"],
|
||||
onclick: _ => { changePage("KEY_VALUE_SECRET_EDIT"); },
|
||||
onclick: () => { changePage("KEY_VALUE_SECRET_EDIT"); },
|
||||
text: i18next.t("kv_secret_edit_btn")
|
||||
}));
|
||||
}
|
||||
|
@ -86,12 +86,12 @@ export class KeyValueSecretPage extends Page {
|
|||
tag: "button",
|
||||
id: "versionsButton",
|
||||
class: ["uk-button", "uk-button-secondary"],
|
||||
onclick: _ => { changePage("KEY_VALUE_VERSIONS"); },
|
||||
onclick: () => { changePage("KEY_VALUE_VERSIONS"); },
|
||||
text: i18next.t("kv_secret_versions_btn")
|
||||
}));
|
||||
}
|
||||
|
||||
getSecret(
|
||||
void getSecret(
|
||||
pageState.currentBaseMount,
|
||||
pageState.currentMountType,
|
||||
pageState.currentSecretPath,
|
||||
|
@ -113,7 +113,7 @@ export class KeyValueSecretPage extends Page {
|
|||
id: "restoreButton",
|
||||
class: ["uk-button", "uk-button-primary"],
|
||||
onclick: () => {
|
||||
undeleteSecret(
|
||||
void undeleteSecret(
|
||||
pageState.currentBaseMount,
|
||||
pageState.currentSecretPath,
|
||||
pageState.currentSecret,
|
||||
|
@ -133,14 +133,18 @@ export class KeyValueSecretPage extends Page {
|
|||
}
|
||||
|
||||
if (isSecretNestedJson) {
|
||||
const jsonText = JSON.stringify(sortedObjectMap(secretsMap as Record<any, any>), null, 4);
|
||||
const jsonText = JSON.stringify(
|
||||
sortedObjectMap(secretsMap as unknown as Record<string, unknown>),
|
||||
null,
|
||||
4
|
||||
);
|
||||
kvList.appendChild(makeElement({
|
||||
tag: "pre",
|
||||
class: ["code-block", "language-json", "line-numbers"],
|
||||
html: Prism.highlight(jsonText, Prism.languages.json, 'json')
|
||||
html: (Prism as { highlight: (text: string, language: null, languageStr: string) => string }).highlight(jsonText, null, 'json')
|
||||
}));
|
||||
} else {
|
||||
secretsMap.forEach((value, key) => {
|
||||
secretsMap.forEach((value: string, key: string) => {
|
||||
const kvListElement = this.makeKVListElement(key, value);
|
||||
kvList.appendChild(kvListElement);
|
||||
}, this);
|
||||
|
|
|
@ -43,7 +43,7 @@ export class KeyValueSecretEditPage extends Page {
|
|||
saveButton
|
||||
]
|
||||
}));
|
||||
getSecret(
|
||||
void getSecret(
|
||||
pageState.currentBaseMount,
|
||||
pageState.currentMountType,
|
||||
pageState.currentSecretPath,
|
||||
|
@ -70,7 +70,7 @@ export class KeyValueSecretEditPage extends Page {
|
|||
).then(_ => {
|
||||
changePage("KEY_VALUE_SECRET");
|
||||
return;
|
||||
}).catch(e => {
|
||||
}).catch((e: Error) => {
|
||||
setErrorText(e.message);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ export class KeyValueVersionsPage extends Page {
|
|||
children: makeElement({
|
||||
tag: "a",
|
||||
text: `v${ver}`,
|
||||
onclick: _ => {
|
||||
onclick: () => {
|
||||
pageState.currentSecretVersion = ver;
|
||||
changePage("KEY_VALUE_SECRET");
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ export class KeyValueViewPage extends Page {
|
|||
children: makeElement({
|
||||
tag: "a",
|
||||
text: secret,
|
||||
onclick: _ => {
|
||||
onclick: () => {
|
||||
if (secret.endsWith("/")) {
|
||||
pageState.pushCurrentSecretPath(secret);
|
||||
changePage("KEY_VALUE_VIEW");
|
||||
|
@ -75,8 +75,9 @@ export class KeyValueViewPage extends Page {
|
|||
})
|
||||
]
|
||||
}));
|
||||
} catch (e) {
|
||||
if (e == DoesNotExistError) {
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
if (error == DoesNotExistError) {
|
||||
// getSecrets also 404's on no keys so dont go all the way back.
|
||||
if (pageState.currentSecretPath.length != 0) {
|
||||
return this.goBack();
|
||||
|
@ -87,7 +88,7 @@ export class KeyValueViewPage extends Page {
|
|||
}));
|
||||
}
|
||||
} else {
|
||||
setErrorText(e.message);
|
||||
setErrorText(error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ export class LoginPage extends Page {
|
|||
tag: "input",
|
||||
class: ["uk-input", "uk-form-width-medium"],
|
||||
attributes: {
|
||||
required: true,
|
||||
required: "true",
|
||||
type: "password",
|
||||
placeholder: i18next.t("token_input"),
|
||||
name: "token"
|
||||
|
@ -45,7 +45,7 @@ export class LoginPage extends Page {
|
|||
id: "usernameInput",
|
||||
class: ["uk-input", "uk-form-width-medium"],
|
||||
attributes: {
|
||||
required: true,
|
||||
required: "true",
|
||||
type: "text",
|
||||
placeholder: i18next.t("username_input"),
|
||||
name: "username"
|
||||
|
@ -56,7 +56,7 @@ export class LoginPage extends Page {
|
|||
id: "passwordInput",
|
||||
class: ["uk-input", "uk-form-width-medium"],
|
||||
attributes: {
|
||||
required: true,
|
||||
required: "true",
|
||||
type: "password",
|
||||
placeholder: i18next.t("password_input"),
|
||||
name: "password"
|
||||
|
@ -127,7 +127,7 @@ export class LoginPage extends Page {
|
|||
pageState.token = token as string;
|
||||
lookupSelf().then(_ => {
|
||||
changePage("HOME");
|
||||
}).catch(e => {
|
||||
}).catch((e: Error) => {
|
||||
document.getElementById("tokenInput").classList.add("uk-form-danger");
|
||||
if (e.message == "permission denied") {
|
||||
setErrorText(i18next.t("token_login_error"));
|
||||
|
@ -145,7 +145,7 @@ export class LoginPage extends Page {
|
|||
).then(res => {
|
||||
pageState.token = res;
|
||||
changePage("HOME");
|
||||
}).catch(e => {
|
||||
}).catch((e: Error) => {
|
||||
document.getElementById("usernameInput").classList.add("uk-form-danger");
|
||||
document.getElementById("passwordInput").classList.add("uk-form-danger");
|
||||
setErrorText(e.message);
|
||||
|
|
|
@ -53,7 +53,7 @@ export class MePage extends Page {
|
|||
onclick: () => {
|
||||
renewSelf().then(() => {
|
||||
changePage("HOME");
|
||||
}).catch(e => {
|
||||
}).catch((e: Error) => {
|
||||
setErrorText(e.message);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { CopyableInputBox, CopyableInputBoxType } from "../elements/CopyableInputBox";
|
||||
import { Margin } from "../elements/Margin";
|
||||
import { Option } from "../elements/Option";
|
||||
import { Page } from "../types/Page";
|
||||
import { makeElement } from "../htmlUtils";
|
||||
import { setPageContent } from "../pageUtils";
|
||||
import i18next from 'i18next';
|
||||
import { Option } from "../elements/Option";
|
||||
|
||||
const passwordLengthMin = 1;
|
||||
const passwordLengthMax = 64;
|
||||
|
@ -55,7 +55,7 @@ export class PwGenPage extends Page {
|
|||
passwordAlphabet: HTMLSelectElement;
|
||||
passwordForm: HTMLFormElement;
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(): void {
|
||||
setPageContent("");
|
||||
this.passwordBox = CopyableInputBox(genPassword(passwordOptionsDefault)) ;
|
||||
|
||||
|
@ -70,9 +70,9 @@ export class PwGenPage extends Page {
|
|||
class: ["uk-range", "uk-width-1-2"],
|
||||
attributes: {
|
||||
type: "range",
|
||||
value: passwordLengthDefault,
|
||||
max: passwordLengthMax,
|
||||
min: passwordLengthMin,
|
||||
value: passwordLengthDefault.toString(),
|
||||
max: passwordLengthMax.toString(),
|
||||
min: passwordLengthMin.toString(),
|
||||
},
|
||||
}) as HTMLInputElement;
|
||||
|
||||
|
@ -124,7 +124,7 @@ export class PwGenPage extends Page {
|
|||
this.passwordLengthTitle.innerText = this.getPasswordLengthText();
|
||||
this.passwordBox.setText(genPassword({
|
||||
length: (this.passwordLengthRange.value as unknown) as number,
|
||||
alphabet: this.passwordAlphabet.value as string,
|
||||
alphabet: this.passwordAlphabet.value ,
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ export class SetLanguagePage extends Page {
|
|||
const language = formData.get("language") as string;
|
||||
pageState.language = language;
|
||||
console.log(pageState.language);
|
||||
i18next.changeLanguage(language).then((t) => {
|
||||
void i18next.changeLanguage(language).then((t) => {
|
||||
changePage("HOME", false);
|
||||
pageState.pageDirection = t("language_direction");
|
||||
location.reload();
|
||||
|
|
|
@ -19,7 +19,7 @@ export class SetVaultURLPage extends Page {
|
|||
tag: "input",
|
||||
class: ["uk-input", "uk-form-width-medium"],
|
||||
attributes: {
|
||||
required: true,
|
||||
required: "true",
|
||||
type: "text",
|
||||
placeholder: "Vault URL",
|
||||
name: "vaultURL"
|
||||
|
|
|
@ -33,7 +33,7 @@ export class NewTOTPPage extends Page {
|
|||
tag: "input",
|
||||
class: ["uk-input", "uk-form-width-medium"],
|
||||
attributes: {
|
||||
required: true,
|
||||
required: "true",
|
||||
type: "text",
|
||||
placeholder: i18next.t("totp_new_name_text"),
|
||||
name: "name"
|
||||
|
@ -89,7 +89,7 @@ export class NewTOTPPage extends Page {
|
|||
};
|
||||
addNewTOTP(pageState.currentBaseMount, parms).then(_ => {
|
||||
changePage("TOTP");
|
||||
}).catch(e => {
|
||||
}).catch((e: Error) => {
|
||||
setErrorText(`API Error: ${e.message}`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,7 +24,7 @@ export class TOTPViewPage extends Page {
|
|||
refresher: number;
|
||||
totpListElements: Record<string, TOTPListElement>;
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(): void {
|
||||
setTitleElement(pageState);
|
||||
const totpList = makeElement({ tag: "div" });
|
||||
setPageContent(makeElement({
|
||||
|
@ -33,7 +33,7 @@ export class TOTPViewPage extends Page {
|
|||
makeElement({
|
||||
tag: "a",
|
||||
text: i18next.t("totp_view_new_btn"),
|
||||
onclick: _ => { changePage("NEW_TOTP"); }
|
||||
onclick: () => { changePage("NEW_TOTP"); }
|
||||
}),
|
||||
makeElement({
|
||||
tag: "p",
|
||||
|
@ -48,14 +48,14 @@ export class TOTPViewPage extends Page {
|
|||
|
||||
|
||||
getTOTPKeys(pageState.currentBaseMount).then(res => {
|
||||
res.forEach(async function (totpKeyName) {
|
||||
const totpListElement = this.makeTOTPListElement(totpKeyName);
|
||||
res.forEach(function (totpKeyName) {
|
||||
const totpListElement = (this as TOTPViewPage).makeTOTPListElement(totpKeyName);
|
||||
totpList.appendChild(totpListElement);
|
||||
this.totpListElements[totpKeyName] = totpListElement;
|
||||
await this.updateTOTPElement(totpKeyName, totpListElement);
|
||||
(this as TOTPViewPage).totpListElements[totpKeyName] = totpListElement;
|
||||
void (this as TOTPViewPage).updateTOTPElement(totpKeyName, totpListElement);
|
||||
}, this);
|
||||
document.getElementById("loadingText").remove();
|
||||
}).catch(e => {
|
||||
}).catch((e: Error) => {
|
||||
if (e == DoesNotExistError) {
|
||||
const loadingText = document.getElementById("loadingText");
|
||||
loadingText.innerText = i18next.t("totp_view_empty");
|
||||
|
@ -64,12 +64,12 @@ export class TOTPViewPage extends Page {
|
|||
}
|
||||
});
|
||||
|
||||
const totpRefresher = async () => {
|
||||
await Promise.all(Array.from(objectToMap(this.totpListElements)).map((kv) => {
|
||||
const totpRefresher = () => {
|
||||
void Promise.all(Array.from(objectToMap(this.totpListElements)).map((kv: [string, TOTPListElement]) => {
|
||||
return this.updateTOTPElement(...kv);
|
||||
}))
|
||||
}
|
||||
await totpRefresher();
|
||||
void totpRefresher();
|
||||
this.refresher = setInterval(totpRefresher, 3000) as unknown as number;
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ export class TOTPViewPage extends Page {
|
|||
children: [totpKeyBox, totpValueBox]
|
||||
}) as TOTPListElement;
|
||||
|
||||
gridElement.setCode = totpValueBox.setText;
|
||||
gridElement.setCode = (code: string) => totpValueBox.setText(code);
|
||||
|
||||
return gridElement;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import { changePage, setErrorText, setPageContent, setTitleElement } from "../..
|
|||
import { fileToBase64, makeElement } from "../../htmlUtils";
|
||||
import { pageState } from "../../globalPageState";
|
||||
import { transitDecrypt } from "../../api/transit/transitDecrypt";
|
||||
import UIkit from 'uikit/dist/js/uikit.min.js';
|
||||
import i18next from "i18next";
|
||||
|
||||
export class TransitDecryptPage extends Page {
|
||||
|
@ -20,7 +19,7 @@ export class TransitDecryptPage extends Page {
|
|||
|
||||
transitDecryptForm: HTMLFormElement;
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(): void {
|
||||
setTitleElement(pageState);
|
||||
setPageContent(makeElement({
|
||||
tag: "div"
|
||||
|
@ -74,7 +73,7 @@ export class TransitDecryptPage extends Page {
|
|||
setPageContent(this.transitDecryptForm);
|
||||
this.transitDecryptForm.addEventListener("submit", async function (e: Event) {
|
||||
e.preventDefault();
|
||||
await this.transitDecryptFormHandler();
|
||||
await (this as TransitDecryptPage).transitDecryptFormHandler();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
|
@ -87,11 +86,11 @@ export class TransitDecryptPage extends Page {
|
|||
|
||||
const ciphertext_file = formData.get("ciphertext_file") as File;
|
||||
if (ciphertext_file.size > 0) {
|
||||
ciphertext = atob((await fileToBase64(ciphertext_file) as string).replace("data:text/plain;base64,", ""));
|
||||
ciphertext = atob((await fileToBase64(ciphertext_file) ).replace("data:text/plain;base64,", ""));
|
||||
}
|
||||
|
||||
try {
|
||||
let res = await transitDecrypt(
|
||||
const res = await transitDecrypt(
|
||||
pageState.currentBaseMount,
|
||||
pageState.currentSecret,
|
||||
{ ciphertext: ciphertext },
|
||||
|
@ -102,9 +101,10 @@ export class TransitDecryptPage extends Page {
|
|||
}
|
||||
const modal = CopyableModal(i18next.t("transit_decrypt_decryption_result_modal_title"), plaintext);
|
||||
document.body.querySelector("#pageContent").appendChild(modal);
|
||||
UIkit.modal(modal).show();
|
||||
} catch (e) {
|
||||
setErrorText(`API Error: ${e.message}`);
|
||||
modal.show();
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(`API Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import { changePage, setErrorText, setPageContent, setTitleElement } from "../..
|
|||
import { fileToBase64, makeElement } from "../../htmlUtils";
|
||||
import { pageState } from "../../globalPageState";
|
||||
import { transitEncrypt } from "../../api/transit/transitEncrypt";
|
||||
import UIkit from 'uikit/dist/js/uikit.min.js';
|
||||
import i18next from "i18next";
|
||||
|
||||
|
||||
|
@ -22,7 +21,7 @@ export class TransitEncryptPage extends Page {
|
|||
transitEncryptForm: HTMLFormElement;
|
||||
|
||||
|
||||
async render(): Promise<void> {
|
||||
render(): void {
|
||||
setTitleElement(pageState);
|
||||
setPageContent(makeElement({
|
||||
tag: "div"
|
||||
|
@ -75,9 +74,9 @@ export class TransitEncryptPage extends Page {
|
|||
}) as HTMLFormElement;
|
||||
setPageContent(this.transitEncryptForm);
|
||||
|
||||
this.transitEncryptForm.addEventListener("submit", async function (e) {
|
||||
this.transitEncryptForm.addEventListener("submit", async function (e: Event) {
|
||||
e.preventDefault();
|
||||
await this.transitEncryptFormHandler();
|
||||
await (this as TransitEncryptPage).transitEncryptFormHandler();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
|
@ -90,23 +89,24 @@ export class TransitEncryptPage extends Page {
|
|||
|
||||
const plaintext_file = formData.get("plaintext_file") as File;
|
||||
if (plaintext_file.size > 0) {
|
||||
plaintext = (await fileToBase64(plaintext_file) as string).replace("data:text/plain;base64,", "");
|
||||
plaintext = (await fileToBase64(plaintext_file) ).replace("data:text/plain;base64,", "");
|
||||
plaintext = base64Checkbox == "on" ? atob(plaintext) : plaintext;
|
||||
} else {
|
||||
plaintext = base64Checkbox == "on" ? plaintext : btoa(plaintext);
|
||||
}
|
||||
|
||||
try {
|
||||
let res = await transitEncrypt(
|
||||
const res = await transitEncrypt(
|
||||
pageState.currentBaseMount,
|
||||
pageState.currentSecret,
|
||||
{ plaintext: plaintext }
|
||||
);
|
||||
const modal = CopyableModal(i18next.t("transit_encrypt_encryption_result_modal_title"), res.ciphertext);
|
||||
document.body.querySelector("#pageContent").appendChild(modal);
|
||||
UIkit.modal(modal).show();
|
||||
} catch (e) {
|
||||
setErrorText(`API Error: ${e.message}`);
|
||||
modal.show();
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(`API Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import { CopyableModal } from "../../elements/CopyableModal";
|
||||
import { FileUploadInput } from "../../elements/FileUploadInput";
|
||||
import { Margin } from "../../elements/Margin";
|
||||
import { Option } from "../../elements/Option";
|
||||
import { Page } from "../../types/Page";
|
||||
import { changePage, setErrorText, setPageContent, setTitleElement } from "../../pageUtils";
|
||||
import { makeElement } from "../../htmlUtils";
|
||||
import { pageState } from "../../globalPageState";
|
||||
import UIkit from 'uikit/dist/js/uikit.min.js';
|
||||
import i18next from "i18next";
|
||||
import { getTransitKey } from "../../api/transit/getTransitKey";
|
||||
import { makeElement } from "../../htmlUtils";
|
||||
import { objectToMap } from "../../utils";
|
||||
import { Option } from "../../elements/Option";
|
||||
import { pageState } from "../../globalPageState";
|
||||
import { transitRewrap } from "../../api/transit/transitRewrap";
|
||||
import i18next from "i18next";
|
||||
|
||||
type versionOption = { version: string; label: string }
|
||||
|
||||
|
@ -27,17 +25,17 @@ export class TransitRewrapPage extends Page {
|
|||
|
||||
async render(): Promise<void> {
|
||||
setTitleElement(pageState);
|
||||
let transitKey = await getTransitKey(pageState.currentBaseMount, pageState.currentSecret);
|
||||
const transitKey = await getTransitKey(pageState.currentBaseMount, pageState.currentSecret);
|
||||
|
||||
let stringVersions = Array.from(objectToMap(transitKey.keys).keys()).reverse() as any as string[];
|
||||
let versions = stringVersions.map((val) => parseInt(val, 10)) as any as number[];
|
||||
const stringVersions = Array.from(objectToMap(transitKey.keys).keys()).reverse() as unknown as string[];
|
||||
const versions = stringVersions.map((val): number => parseInt(val, 10));
|
||||
|
||||
// get the selectable version options in the same
|
||||
// format the official UI uses.
|
||||
// e.g: ["2 (latest)", "1"]
|
||||
|
||||
let options: versionOption[] = versions.map((val): versionOption => {
|
||||
let i18nkey = val == Math.max(...versions) ?
|
||||
const options: versionOption[] = versions.map((val): versionOption => {
|
||||
const i18nkey = val == Math.max(...versions) ?
|
||||
"transit_rewrap_latest_version_option_text"
|
||||
:
|
||||
"transit_rewrap_version_option_text";
|
||||
|
@ -83,15 +81,14 @@ export class TransitRewrapPage extends Page {
|
|||
setPageContent(this.transitRewrapForm);
|
||||
this.transitRewrapForm.addEventListener("submit", async function (e: Event) {
|
||||
e.preventDefault();
|
||||
await this.transitRewrapFormHandler();
|
||||
await (this as TransitRewrapPage).transitRewrapFormHandler();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
async transitRewrapFormHandler(): Promise<void> {
|
||||
const formData = new FormData(this.transitRewrapForm);
|
||||
const ciphertext = formData.get("ciphertext") as string;
|
||||
try {
|
||||
let res = await transitRewrap(
|
||||
const res = await transitRewrap(
|
||||
pageState.currentBaseMount,
|
||||
pageState.currentSecret,
|
||||
{
|
||||
|
@ -101,9 +98,10 @@ export class TransitRewrapPage extends Page {
|
|||
);
|
||||
const modal = CopyableModal(i18next.t("transit_rewrap_result_modal_title"), res.ciphertext);
|
||||
document.body.querySelector("#pageContent").appendChild(modal);
|
||||
UIkit.modal(modal).show();
|
||||
} catch (e) {
|
||||
setErrorText(`API Error: ${e.message}`);
|
||||
modal.show();
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
setErrorText(`API Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ export class TransitViewPage extends Page {
|
|||
children: makeElement({
|
||||
tag: "a",
|
||||
text: secret,
|
||||
onclick: _ => {
|
||||
onclick: () => {
|
||||
pageState.currentSecret = secret;
|
||||
changePage("TRANSIT_VIEW_SECRET");
|
||||
}
|
||||
|
@ -55,14 +55,15 @@ export class TransitViewPage extends Page {
|
|||
})
|
||||
]
|
||||
}));
|
||||
} catch (e) {
|
||||
if (e == DoesNotExistError) {
|
||||
} catch (e: unknown) {
|
||||
const error = e as Error;
|
||||
if (error == DoesNotExistError) {
|
||||
transitViewContent.appendChild(makeElement({
|
||||
tag: "p",
|
||||
text: i18next.t("transit_view_none_here_text")
|
||||
}));
|
||||
} else {
|
||||
setErrorText(e.message);
|
||||
setErrorText(error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Page } from "../../types/Page";
|
||||
import { Tile } from "../../elements/Tile";
|
||||
import { changePage, setPageContent, setTitleElement } from "../../pageUtils";
|
||||
import { getTransitKey } from "../../api/transit/getTransitKey";
|
||||
import { makeElement } from "../../htmlUtils";
|
||||
import { pageState } from "../../globalPageState";
|
||||
import i18next from 'i18next';
|
||||
import { getTransitKey } from "../../api/transit/getTransitKey";
|
||||
import { Tile } from "../../elements/Tile";
|
||||
|
||||
export class TransitViewSecretPage extends Page {
|
||||
constructor() {
|
||||
|
@ -18,7 +18,7 @@ export class TransitViewSecretPage extends Page {
|
|||
async render(): Promise<void> {
|
||||
setTitleElement(pageState);
|
||||
|
||||
let transitKey = await getTransitKey(pageState.currentBaseMount, pageState.currentSecret);
|
||||
const transitKey = await getTransitKey(pageState.currentBaseMount, pageState.currentSecret);
|
||||
|
||||
setPageContent(makeElement({
|
||||
tag: "div",
|
||||
|
|
|
@ -41,9 +41,16 @@ export class UnsealPage extends Page {
|
|||
}
|
||||
|
||||
makeRefresher(): void {
|
||||
this.refresher = setInterval(async function () {
|
||||
this.updateSealProgress(await getSealStatus());
|
||||
}.bind(this), 1000) as unknown as number;
|
||||
const id = setInterval(() => {
|
||||
void (this as UnsealPage).doRefresh().then(() => {});
|
||||
return;
|
||||
}, 1000);
|
||||
this.refresher = id as unknown as number;
|
||||
}
|
||||
|
||||
async doRefresh(): Promise<void> {
|
||||
const status = await getSealStatus();
|
||||
this.updateSealProgress(status);
|
||||
}
|
||||
|
||||
async render(): Promise<void> {
|
||||
|
@ -58,7 +65,7 @@ export class UnsealPage extends Page {
|
|||
}) as HTMLParagraphElement;
|
||||
this.unsealInputContent = makeElement({
|
||||
tag: "div"
|
||||
}) as HTMLElement;
|
||||
});
|
||||
setPageContent(makeElement({
|
||||
tag: "div",
|
||||
children: [
|
||||
|
@ -103,7 +110,7 @@ export class UnsealPage extends Page {
|
|||
this.deinitWebcam();
|
||||
this.unsealInputContent.querySelectorAll('*').forEach(n => n.remove())
|
||||
if (method == UnsealInputModes.FORM_INPUT) this.makeUnsealForm();
|
||||
if (method == UnsealInputModes.QR_INPUT) this.makeQRInput();
|
||||
if (method == UnsealInputModes.QR_INPUT) void this.makeQRInput();
|
||||
this.setButtons(method);
|
||||
}
|
||||
|
||||
|
@ -115,7 +122,7 @@ export class UnsealPage extends Page {
|
|||
tag: "input",
|
||||
class: ["uk-input", "uk-form-width-medium"],
|
||||
attributes: {
|
||||
required: true,
|
||||
required: "true",
|
||||
type: "password",
|
||||
placeholder: i18next.t("key_input_placeholder"),
|
||||
name: "key"
|
||||
|
@ -129,15 +136,15 @@ export class UnsealPage extends Page {
|
|||
]
|
||||
}) as HTMLFormElement;
|
||||
this.unsealInputContent.appendChild(this.unsealKeyForm);
|
||||
this.unsealKeyForm.addEventListener("submit", function (e) {
|
||||
this.unsealKeyForm.addEventListener("submit", function (e: Event) {
|
||||
e.preventDefault();
|
||||
this.handleKeySubmit();
|
||||
void (this as UnsealPage).handleKeySubmit();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
async makeQRInput(): Promise<void> {
|
||||
this.qrScanner = await QRScanner(function (code: string) {
|
||||
this.submitKey(code);
|
||||
(this as UnsealPage).submitKey(code);
|
||||
console.log('decoded qr code:', code)
|
||||
}.bind(this));
|
||||
this.unsealInputContent.appendChild(this.qrScanner);
|
||||
|
@ -162,15 +169,15 @@ export class UnsealPage extends Page {
|
|||
|
||||
submitKey(key: string): void {
|
||||
submitUnsealKey(key).then(_ => {
|
||||
getSealStatus().then(data => {
|
||||
this.updateSealProgress(data);
|
||||
void getSealStatus().then(data => {
|
||||
void this.updateSealProgress(data);
|
||||
});
|
||||
}).catch(e => {
|
||||
}).catch((e: Error) => {
|
||||
setErrorText(e.message);
|
||||
});
|
||||
}
|
||||
|
||||
async handleKeySubmit(): Promise<void> {
|
||||
handleKeySubmit(): void {
|
||||
const formData = new FormData(this.unsealKeyForm);
|
||||
|
||||
this.submitKey(formData.get("key") as string)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { PageState } from "./PageState";
|
||||
import { pageState } from "./globalPageState";
|
||||
import i18next from 'i18next';
|
||||
|
||||
|
@ -6,9 +7,13 @@ import i18next from 'i18next';
|
|||
// before rendering.
|
||||
// Also it only runs when process.env.NODE_ENV == "development"
|
||||
|
||||
// Please empty this function before committing.
|
||||
export async function playground(): Promise<void> {
|
||||
console.log("Welcome to Playground!");
|
||||
(window as any).pageState = pageState;
|
||||
(window as any).i18next = i18next;
|
||||
declare global {
|
||||
interface Window { pageState: PageState; i18next: unknown; }
|
||||
}
|
||||
|
||||
// Please empty this function before committing.
|
||||
export function playground(): void {
|
||||
console.log("Welcome to Playground!");
|
||||
window.pageState = pageState;
|
||||
window.i18next = i18next;
|
||||
}
|
||||
|
|
|
@ -4,8 +4,9 @@ export class Page {
|
|||
constructor() {
|
||||
// Do Nothing
|
||||
}
|
||||
render(): any {
|
||||
render(): unknown {
|
||||
// Do Nothing
|
||||
return null;
|
||||
}
|
||||
get name(): string {
|
||||
return "Page";
|
||||
|
|
|
@ -5,13 +5,13 @@ export function removeDoubleSlash(str: string): string {
|
|||
export const getObjectKeys =
|
||||
(obj: Record<string, unknown>): string[] => Object.getOwnPropertyNames(obj);
|
||||
export const objectToMap =
|
||||
(obj: Record<any, any>): Map<any, any> => new Map(Object.entries(obj));
|
||||
(obj: Record<string, unknown>): Map<string, unknown> => new Map(Object.entries(obj));
|
||||
export const sortedObjectMap =
|
||||
(obj: Record<string, unknown>): Map<any, any> => new Map(Object.entries(obj).sort());
|
||||
(obj: Record<string, unknown>): Map<string, unknown> => new Map(Object.entries(obj).sort());
|
||||
|
||||
export function getKeyByObjectPropertyValue(map: Record<string, unknown>, searchValue: unknown): string {
|
||||
for (const key of getObjectKeys(map)) {
|
||||
if ((map as any)[key] === searchValue)
|
||||
if (map[key] === searchValue)
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue