1
0
Fork 0

Start work on transit pages.

This commit is contained in:
Kitteh 2021-04-15 15:09:43 +01:00
parent 9f40b0b22c
commit 6c6a92b094
7 changed files with 386 additions and 240 deletions

View file

@ -4,301 +4,317 @@ import { getAPIURL, getToken, removeDoubleSlash } from "./utils.js";
export const DoesNotExistError = new Error("Does not exist."); export const DoesNotExistError = new Error("Does not exist.");
export async function lookupSelf() { export async function lookupSelf() {
const request = new Request(getAPIURL() + "/v1/auth/token/lookup-self", { const request = new Request(getAPIURL() + "/v1/auth/token/lookup-self", {
headers: { headers: {
"X-Vault-Token": getToken(), "X-Vault-Token": getToken(),
} }
}); });
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
if ("data" in data) { if ("data" in data) {
return data.data; return data.data;
} else if ("errors" in data) { } else if ("errors" in data) {
throw new Error(data.errors[0]); throw new Error(data.errors[0]);
} }
}); });
} }
export async function renewSelf() { export async function renewSelf() {
const request = new Request(getAPIURL() + "/v1/auth/token/renew-self", { const request = new Request(getAPIURL() + "/v1/auth/token/renew-self", {
method: 'POST', method: 'POST',
headers: { headers: {
"X-Vault-Token": getToken(), "X-Vault-Token": getToken(),
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({}) body: JSON.stringify({})
}); });
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
if ("errors" in data) { if ("errors" in data) {
throw new Error(data.errors[0]); throw new Error(data.errors[0]);
} }
}); });
} }
export async function usernameLogin(username, password) { export async function usernameLogin(username, password) {
const request = new Request(getAPIURL() + `/v1/auth/userpass/login/${username}`, { const request = new Request(getAPIURL() + `/v1/auth/userpass/login/${username}`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}, },
body: JSON.stringify({ "username": username, "password": password }) body: JSON.stringify({ "username": username, "password": password })
}); });
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
if ("auth" in data) { if ("auth" in data) {
return data.auth.client_token; return data.auth.client_token;
} else if ("errors" in data) { } else if ("errors" in data) {
throw new Error(data.errors[0]); throw new Error(data.errors[0]);
} }
}); });
} }
export async function getMounts() { export async function getMounts() {
const request = new Request(getAPIURL() + "/v1/sys/internal/ui/mounts", { const request = new Request(getAPIURL() + "/v1/sys/internal/ui/mounts", {
headers: { headers: {
"X-Vault-Token": getToken(), "X-Vault-Token": getToken(),
} }
}); });
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
return data.data.secret; return data.data.secret;
}); });
} }
export async function getSealStatus() { export async function getSealStatus() {
const request = new Request(getAPIURL() + "/v1/sys/seal-status"); const request = new Request(getAPIURL() + "/v1/sys/seal-status");
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
return data; return data;
}); });
} }
export async function submitUnsealKey(key) { export async function submitUnsealKey(key) {
const request = new Request(getAPIURL() + "/v1/sys/unseal", { const request = new Request(getAPIURL() + "/v1/sys/unseal", {
method: "POST", method: "POST",
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ body: JSON.stringify({
"key": key "key": key
}) })
}); });
let response = await fetch(request); let response = await fetch(request);
if (!response.ok) { if (!response.ok) {
let json = await response.json(); let json = await response.json();
throw new Error(json.errors[0]); throw new Error(json.errors[0]);
} }
} }
export async function getCapabilities(baseMount, secretPath, name) { export async function getCapabilities(baseMount, secretPath, name) {
const request = new Request(getAPIURL() + "/v1/sys/capabilities-self", { const request = new Request(getAPIURL() + "/v1/sys/capabilities-self", {
method: "POST", method: "POST",
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
"X-Vault-Token": getToken(), "X-Vault-Token": getToken(),
}, },
body: JSON.stringify( body: JSON.stringify(
{ {
"paths": [removeDoubleSlash(baseMount + secretPath.join("/") + "/" + name)] "paths": [removeDoubleSlash(baseMount + secretPath.join("/") + "/" + name)]
} }
) )
}); });
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
return data.capabilities; return data.capabilities;
}); });
} }
export async function getSecrets(baseMount, secretPath) { export async function getSecrets(baseMount, secretPath) {
let secretURL = ""; let secretURL = "";
if (pageState.currentMountType == "kv-v2") { if (pageState.currentMountType == "kv-v2") {
secretURL = `/v1/${baseMount}/metadata/${secretPath.join("")}?list=true`; secretURL = `/v1/${baseMount}/metadata/${secretPath.join("")}?list=true`;
} else { } else {
// cubbyhole and v1 are identical // cubbyhole and v1 are identical
secretURL = `/v1/${baseMount}/${secretPath.join("")}?list=true`; secretURL = `/v1/${baseMount}/${secretPath.join("")}?list=true`;
}
const request = new Request(getAPIURL() + secretURL, {
headers: {
"X-Vault-Token": getToken(),
} }
const request = new Request(getAPIURL() + secretURL, { });
headers: { return fetch(request).then(response => {
"X-Vault-Token": getToken(), if (response.status == 404) {
} throw DoesNotExistError;
}); }
return fetch(request).then(response => { return response.json();
if (response.status == 404) { }).then(data => {
throw DoesNotExistError; return data.data.keys;
} });
return response.json();
}).then(data => {
return data.data.keys;
});
} }
export async function getSecretMetadata(baseMount, secretPath, name) { export async function getSecretMetadata(baseMount, secretPath, name) {
const request = new Request(getAPIURL() + `/v1/${baseMount}/metadata/${secretPath.join("")}/${name}`, { const request = new Request(getAPIURL() + `/v1/${baseMount}/metadata/${secretPath.join("")}/${name}`, {
headers: { headers: {
"X-Vault-Token": getToken(), "X-Vault-Token": getToken(),
} }
}); });
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
return data.data; return data.data;
}); });
} }
export async function undeleteSecret(baseMount, secretPath, name, version) { export async function undeleteSecret(baseMount, secretPath, name, version) {
let secretURL = `/v1/${baseMount}/undelete/${secretPath.join("")}/${name}`; let secretURL = `/v1/${baseMount}/undelete/${secretPath.join("")}/${name}`;
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, ""); secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
let request = new Request(getAPIURL() + secretURL, { let request = new Request(getAPIURL() + secretURL, {
method: "POST", method: "POST",
headers: { headers: {
'X-Vault-Token': getToken(), 'X-Vault-Token': getToken(),
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ "versions": [version] }) body: JSON.stringify({ "versions": [version] })
}); });
let response = await fetch(request); let response = await fetch(request);
if (!response.ok) { if (!response.ok) {
let json = await response.json(); let json = await response.json();
throw new Error(json.errors[0]); throw new Error(json.errors[0]);
} }
} }
export async function getSecret(baseMount, secretPath, name, version = "0") { export async function getSecret(baseMount, secretPath, name, version = "0") {
let secretURL = ""; let secretURL = "";
if (pageState.currentMountType == "kv-v2") { if (pageState.currentMountType == "kv-v2") {
secretURL = `/v1/${baseMount}/data/${secretPath.join("")}/${name}`; secretURL = `/v1/${baseMount}/data/${secretPath.join("")}/${name}`;
if (version != 0) secretURL += `?version=${version}`; if (version != 0) secretURL += `?version=${version}`;
} else { } else {
secretURL = `/v1/${baseMount}/${secretPath.join("")}/${name}`; secretURL = `/v1/${baseMount}/${secretPath.join("")}/${name}`;
}
const request = new Request(getAPIURL() + secretURL, {
headers: {
"X-Vault-Token": getToken(),
} }
const request = new Request(getAPIURL() + secretURL, { });
headers: {
"X-Vault-Token": getToken(),
}
});
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
return pageState.currentMountType == "kv-v2" ? data.data.data : data.data; return pageState.currentMountType == "kv-v2" ? data.data.data : data.data;
}); });
} }
export async function deleteSecret(baseMount, secretPath, name, version) { export async function deleteSecret(baseMount, secretPath, name, version) {
let secretURL = ""; let secretURL = "";
let request; let request;
if (pageState.currentMountType == "kv-v2" && version != "0") { if (pageState.currentMountType == "kv-v2" && version != "0") {
secretURL = `/v1/${baseMount}/delete/${secretPath.join("")}/${name}`; secretURL = `/v1/${baseMount}/delete/${secretPath.join("")}/${name}`;
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, ""); secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
request = new Request(getAPIURL() + secretURL, { request = new Request(getAPIURL() + secretURL, {
method: "POST", method: "POST",
headers: { headers: {
'X-Vault-Token': getToken(), 'X-Vault-Token': getToken(),
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: JSON.stringify({ "versions": [version] }) body: JSON.stringify({ "versions": [version] })
}); });
} else {
if (pageState.currentMountType == "kv-v2") {
secretURL = `/v1/${baseMount}/metadata/${secretPath.join("")}/${name}`;
} else { } else {
if (pageState.currentMountType == "kv-v2") { secretURL = `/v1/${baseMount}/${secretPath.join("")}/${name}`;
secretURL = `/v1/${baseMount}/metadata/${secretPath.join("")}/${name}`;
} else {
secretURL = `/v1/${baseMount}/${secretPath.join("")}/${name}`;
}
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
request = new Request(getAPIURL() + secretURL, {
method: "DELETE",
headers: {
'X-Vault-Token': getToken()
},
});
} }
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
request = new Request(getAPIURL() + secretURL, {
method: "DELETE",
headers: {
'X-Vault-Token': getToken()
},
});
}
let response = await fetch(request); let response = await fetch(request);
if (!response.ok) { if (!response.ok) {
let json = await response.json(); let json = await response.json();
throw new Error(json.errors[0]); throw new Error(json.errors[0]);
} }
} }
export async function createOrUpdateSecret(baseMount, secretPath, name, data) { export async function createOrUpdateSecret(baseMount, secretPath, name, data) {
let secretURL = ""; let secretURL = "";
let APIData = {}; let APIData = {};
if (pageState.currentMountType == "kv-v2") { if (pageState.currentMountType == "kv-v2") {
secretURL = `/v1/${baseMount}/data/${secretPath.join("")}/${name}`; secretURL = `/v1/${baseMount}/data/${secretPath.join("")}/${name}`;
APIData = { "data": data }; APIData = { "data": data };
} else { } else {
secretURL = `/v1/${baseMount}/${secretPath.join("")}/${name}`; secretURL = `/v1/${baseMount}/${secretPath.join("")}/${name}`;
APIData = data; APIData = data;
} }
secretURL = removeDoubleSlash(secretURL).replace(/\/$/, ""); secretURL = removeDoubleSlash(secretURL).replace(/\/$/, "");
const request = new Request(getAPIURL() + secretURL, { const request = new Request(getAPIURL() + secretURL, {
method: "POST", method: "POST",
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Vault-Token': getToken() 'X-Vault-Token': getToken()
}, },
body: JSON.stringify(APIData, null, 0) body: JSON.stringify(APIData, null, 0)
}); });
let response = await fetch(request); let response = await fetch(request);
if (!response.ok) { if (!response.ok) {
let json = await response.json(); let json = await response.json();
throw new Error(json.errors[0]); throw new Error(json.errors[0]);
}
}
export async function getTransitKeys(baseMount) {
const request = new Request(getAPIURL() + `/v1/${baseMount}/keys?list=true`, {
headers: {
"X-Vault-Token": getToken(),
} }
});
return fetch(request).then(response => {
if (response.status == 404) {
throw DoesNotExistError;
}
return response.json();
}).then(data => {
return data.data.keys;
});
} }
export async function getTOTPKeys(baseMount) { export async function getTOTPKeys(baseMount) {
const request = new Request(getAPIURL() + `/v1/${baseMount}/keys?list=true`, { const request = new Request(getAPIURL() + `/v1/${baseMount}/keys?list=true`, {
headers: { headers: {
"X-Vault-Token": getToken(), "X-Vault-Token": getToken(),
} }
}); });
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
return data.data.keys; return data.data.keys;
}); });
} }
export async function getTOTPCode(baseMount, name) { export async function getTOTPCode(baseMount, name) {
const request = new Request(getAPIURL() + `/v1/${baseMount}/code/${name}`, { const request = new Request(getAPIURL() + `/v1/${baseMount}/code/${name}`, {
headers: { headers: {
"X-Vault-Token": getToken(), "X-Vault-Token": getToken(),
} }
}); });
return fetch(request).then(response => { return fetch(request).then(response => {
return response.json(); return response.json();
}).then(data => { }).then(data => {
return data.data.code; return data.data.code;
}); });
} }
export async function addNewTOTP(baseMount, parms) { export async function addNewTOTP(baseMount, parms) {
const request = new Request(getAPIURL() + removeDoubleSlash(`/v1/${baseMount}/keys/${parms.name}`), { const request = new Request(getAPIURL() + removeDoubleSlash(`/v1/${baseMount}/keys/${parms.name}`), {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'X-Vault-Token': getToken() 'X-Vault-Token': getToken()
}, },
body: JSON.stringify(parms) body: JSON.stringify(parms)
}); });
let response = await fetch(request); let response = await fetch(request);
if (!response.ok) { if (!response.ok) {
let json = await response.json(); let json = await response.json();
throw new Error(json.errors[0]); throw new Error(json.errors[0]);
} }
} }

View file

@ -23,6 +23,8 @@ import {
LoginPage, LoginPage,
SetVaultURLPage, SetVaultURLPage,
UnsealPage, UnsealPage,
TransitViewPage,
TransitViewSecretPage,
KeyValueViewPage, KeyValueViewPage,
KeyValueSecretsPage, KeyValueSecretsPage,
KeyValueVersionsPage, KeyValueVersionsPage,
@ -41,6 +43,8 @@ const pages = {
LOGIN: new LoginPage(), LOGIN: new LoginPage(),
SET_VAULT_URL: new SetVaultURLPage(), SET_VAULT_URL: new SetVaultURLPage(),
UNSEAL: new UnsealPage(), UNSEAL: new UnsealPage(),
TRANSIT_VIEW: new TransitViewPage(),
TRANSIT_VIEW_SECRET: new TransitViewSecretPage(),
KEY_VALUE_VIEW: new KeyValueViewPage(), KEY_VALUE_VIEW: new KeyValueViewPage(),
KEY_VALUE_SECRETS: new KeyValueSecretsPage(), KEY_VALUE_SECRETS: new KeyValueSecretsPage(),
KEY_VALUE_VERSIONS: new KeyValueVersionsPage(), KEY_VALUE_VERSIONS: new KeyValueVersionsPage(),

View file

@ -122,7 +122,7 @@ export class HomePage extends Page {
if (typeof mount != 'object') return; if (typeof mount != 'object') return;
if (mount == null) return; if (mount == null) return;
if (!("type" in mount)) return; if (!("type" in mount)) return;
if (!(["kv", "totp"].includes(mount.type))) return; if (!(["kv", "totp", "transit"].includes(mount.type))) return;
let mountType = mount.type == "kv" ? "kv-v" + String(mount.options.version) : mount.type; let mountType = mount.type == "kv" ? "kv-v" + String(mount.options.version) : mount.type;
@ -134,6 +134,9 @@ export class HomePage extends Page {
} else if (mount.type == "totp") { } else if (mount.type == "totp") {
linkText = `TOTP - ${baseMount}`; linkText = `TOTP - ${baseMount}`;
linkPage = pages.TOTP; linkPage = pages.TOTP;
} else if (mount.type == "transit"){
linkText = `Transit - ${baseMount}`;
linkPage = pages.TRANSIT_VIEW;
} }
navList.appendChild(makeElement({ navList.appendChild(makeElement({

View file

@ -71,7 +71,7 @@ export class KeyValueViewPage extends Page {
} else { } else {
setErrorText(e.message); setErrorText(e.message);
} }
}; }
} }
get name() { get name() {

65
src/pages/TransitView.js Normal file
View file

@ -0,0 +1,65 @@
import { Page } from "../types/Page.js";
import { DoesNotExistError, getTransitKeys } from "../api.js";
import { setErrorText, setTitleElement } from "../pageUtils.js";
import { makeElement } from "../htmlUtils.js";
export class TransitViewPage extends Page {
constructor() {
super();
}
goBack() {
changePage(pages.HOME);
}
async render() {
pageState.currentSecret = "";
setTitleElement(pageState);
let newButton = makeElement({
tag: "button",
text: "New",
class: ["uk-button", "uk-button-primary", "uk-margin-bottom"],
onclick: () => {
changePage(pages.TRANSIT_NEW_KEY);
}
});
pageContent.appendChild(newButton);
try {
let res = await getTransitKeys(pageState.currentBaseMount);
pageContent.appendChild(makeElement({
tag: "ul",
class: ["uk-nav", "uk-nav-default"],
children: [
...res.map(function (secret) {
return makeElement({
tag: "li",
children: makeElement({
tag: "a",
text: secret,
onclick: _ => {
pageState.currentSecret = secret;
changePage(pages.TRANSIT_VIEW_SECRET);
}
})
});
})
]
}));
} catch (e) {
if (e == DoesNotExistError) {
pageContent.appendChild(makeElement({
tag: "p",
text: "You seem to have no transit keys here, would you like to create one?"
}));
} else {
setErrorText(e.message);
}
}
}
get name() {
return "Transit View";
}
}

View file

@ -0,0 +1,56 @@
import { Page } from "../types/Page.js";
import { setPageContent, setTitleElement } from "../pageUtils.js";
import { makeElement } from "../htmlUtils.js";
export class TransitViewSecretPage extends Page {
constructor() {
super();
}
makeTile(title, description, onclick) {
return makeElement({
tag: "div",
class: ["uk-tile", "uk-tile-default", "uk-tile-primary", "uk-padding-small"],
children: makeElement({
tag: "a",
class: "uk-link-heading",
children: [
makeElement({
tag: "p",
class: "uk-h4",
text: title
}),
makeElement({
tag: "span",
class: "uk-text-muted",
text: description
})
]
})
});
}
async render() {
setTitleElement(pageState);
setPageContent(makeElement({
tag: "div",
class: ["uk-child-width-1-2", "uk-grid-collapse", "uk-grid-small"],
attributes: { "uk-grid": "" },
children: [
makeElement({
tag: "div",
children: [
this.makeTile("Encrypt", "Encrypt some plaintext or base64 encoded binary."),
this.makeTile("Decrypt", "Decrypt some cyphertext."),
]
}),
]
}));
}
get name() {
return "Password Generator";
}
}

View file

@ -10,4 +10,6 @@ export { KeyValueVersionsPage } from "./KeyValueVersions.js";
export { KeyValueNewPage } from "./KeyValueNew.js"; export { KeyValueNewPage } from "./KeyValueNew.js";
export { KeyValueDeletePage } from "./KeyValueDelete.js"; export { KeyValueDeletePage } from "./KeyValueDelete.js";
export { KeyValueSecretsEditPage } from "./KeyValueSecretsEdit.js"; export { KeyValueSecretsEditPage } from "./KeyValueSecretsEdit.js";
export { PwGenPage } from "./PwGen.js"; export { PwGenPage } from "./PwGen.js";
export { TransitViewPage } from "./TransitView.js";
export { TransitViewSecretPage } from "./TransitViewSecret.js";