diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..287a67e --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +VITE_AKEYLESS_ACCESS_ID="" +VITE_AKEYLESS_ACCESS_KEY="" +VITE_AKEYLESS_KEY_PATH="" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8a48f2b..1cac559 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,4 @@ dist-ssr *.njsproj *.sln *.sw? -tokens.ts \ No newline at end of file +.env \ No newline at end of file diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..b15b3a2 --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,12 @@ +/// + +interface ImportMetaEnv { + readonly VITE_AKEYLESS_KEY_PATH: string + readonly VITE_AKEYLESS_ACCESS_ID: string + readonly VITE_AKEYLESS_ACCESS_KEY: string + // more env variables... + } + + interface ImportMeta { + readonly env: ImportMetaEnv + } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index fa52e6a..afce62b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,7 +2,4 @@ import "./style.css"; import { tokenList } from "./tokenList"; import rootDiv from "./utils/root"; - -rootDiv!.innerHTML = ` - ${tokenList()} -`; +rootDiv!.innerHTML = await tokenList(); diff --git a/src/toast.ts b/src/toast.ts index 86e1815..ca57a63 100644 --- a/src/toast.ts +++ b/src/toast.ts @@ -2,6 +2,11 @@ export function toast(element: HTMLDivElement, message: string) { // Target our predefined DIV that will hold toast messages. const toastDiv = element.getElementsByClassName('toast') + const interval = setInterval(() => { + toastDiv[0].remove() + clearInterval(interval) + }, 5000) + // If we currently have a toast displayed, let's remove it from the DOM. if (toastDiv && toastDiv.length != 0) { for (const el of toastDiv){ diff --git a/src/token.ts b/src/token.ts index 704bb65..34b029e 100644 --- a/src/token.ts +++ b/src/token.ts @@ -1,7 +1,6 @@ import totp from 'totp-generator' const period = 30 const digits = 6 - export function displayToken(secret: string) { const token = totp(secret.replace(/ /g, '').trim(), { digits, diff --git a/src/tokenList.ts b/src/tokenList.ts index dd8b529..0f36191 100644 --- a/src/tokenList.ts +++ b/src/tokenList.ts @@ -1,8 +1,9 @@ import { displayTokenListItem } from "./tokenListItem"; -import { tokens } from "./tokens"; +import { Token, decryptTokensWithAkeyless } from "./utils/api"; -export function tokenList() { - return `
${tokens.map((token) => +export async function tokenList() { + const decryptedTokens = (await decryptTokensWithAkeyless(import.meta.env.VITE_AKEYLESS_KEY_PATH)) + return `${decryptedTokens.map((token: Token) => displayTokenListItem(token.account, token.secret) )}
`; } diff --git a/src/tokens.ts b/src/tokens.ts new file mode 100644 index 0000000..af110e9 --- /dev/null +++ b/src/tokens.ts @@ -0,0 +1 @@ +export const tokens = "AQAAAAEIAd3tVg6Vbzp/2fXBP6JdFoK7A5fu5n8daqwUzGKK3CgAYW+SujAoXcK5R3QgGkUp34Vi/DEtjOU9WNd3vGIMZAUQhngRqDS0rfK3i8kN4/C5oBjhkYhWKY6ABbJtmnI9p4EzfnC5RkZlSpHFNK6yAxk2jJVAFU6ynXkqVZKLamtf+aViyYyX8wI=" \ No newline at end of file diff --git a/src/utils/api.ts b/src/utils/api.ts new file mode 100644 index 0000000..3b5d867 --- /dev/null +++ b/src/utils/api.ts @@ -0,0 +1,68 @@ +import { tokens } from "../tokens"; + +export interface TokenResponse { + token: string; + creds: null; +} + +export interface Token { + account: string; + secret: string; + } + +export interface GenericAPIResponse { + result: string; +} + +const baseUrl = 'https://api.akeyless.io' +async function fetchAkeylessAuthToken(): Promise { + + const options = { + method: 'POST', + headers: {accept: 'application/json', 'content-type': 'application/json'}, + body: JSON.stringify({ + 'access-type': 'access_key', + 'gcp-audience': 'akeyless.io', + json: false, + 'access-id': import.meta.env.VITE_AKEYLESS_ACCESS_ID, + 'access-key': import.meta.env.VITE_AKEYLESS_ACCESS_KEY + }) + }; + const token = await fetch(`${baseUrl}/auth`, options) + return await token.json() + +} + +async function encryptTokensWithAkeyless(encryptionKeyName: string): Promise{ + const options = { + method: 'POST', + headers: {accept: 'application/json', 'content-type': 'application/json'}, + body: JSON.stringify({ + json: false, + 'key-name': encryptionKeyName, + plaintext: JSON.stringify(tokens), + token: (await fetchAkeylessAuthToken()).token + }) + }; + + const response = await fetch(`${baseUrl}/encrypt`, options) + return await response.json() +} + +async function decryptTokensWithAkeyless(encryptionKeyName: string): Promise{ + const options = { + method: 'POST', + headers: {accept: 'application/json', 'content-type': 'application/json'}, + body: JSON.stringify({ + json: false, + 'key-name': encryptionKeyName, + ciphertext: tokens, + token: (await fetchAkeylessAuthToken()).token + }) + }; + + const response = await fetch(`${baseUrl}/decrypt`, options) + const decodedTokens = await response.json() + return JSON.parse(decodedTokens.result) +} +export {fetchAkeylessAuthToken, encryptTokensWithAkeyless, decryptTokensWithAkeyless} \ No newline at end of file