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

View file

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

View file

@ -122,7 +122,7 @@ export class HomePage extends Page {
if (typeof mount != 'object') return;
if (mount == null) 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;
@ -134,6 +134,9 @@ export class HomePage extends Page {
} else if (mount.type == "totp") {
linkText = `TOTP - ${baseMount}`;
linkPage = pages.TOTP;
} else if (mount.type == "transit"){
linkText = `Transit - ${baseMount}`;
linkPage = pages.TRANSIT_VIEW;
}
navList.appendChild(makeElement({

View file

@ -71,7 +71,7 @@ export class KeyValueViewPage extends Page {
} else {
setErrorText(e.message);
}
};
}
}
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 { KeyValueDeletePage } from "./KeyValueDelete.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";