-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5d0ec4c
commit b3a9dfe
Showing
8 changed files
with
177 additions
and
5 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,103 @@ | ||
export interface SecretValue { | ||
name: string; | ||
value: string | undefined; | ||
} | ||
|
||
export interface SecretProvider { | ||
get(env: string, name: string): Promise<SecretValue>; | ||
getPrefix(env: string, prefix: string): Promise<SecretValue[]>; | ||
} | ||
|
||
export class NoopSecretProvider implements SecretProvider { | ||
get(_: string, name: string): Promise<SecretValue> { | ||
const paths = name.split("/"); | ||
const secretName = paths[paths.length - 1]; | ||
return Promise.resolve({ | ||
name: secretName, | ||
value: undefined, | ||
}); | ||
} | ||
|
||
getPrefix(_: string, __: string): Promise<SecretValue[]> { | ||
return Promise.resolve([]); | ||
} | ||
} | ||
|
||
export class Context { | ||
env: string; | ||
configs: any; | ||
secrets: any; | ||
secretProvider: SecretProvider; | ||
|
||
constructor(configs: any = {}, secrets: any = {}) { | ||
constructor( | ||
env: string, | ||
configs: any = {}, | ||
secretProvider: SecretProvider = new NoopSecretProvider(), | ||
) { | ||
this.env = env; | ||
this.configs = configs; | ||
this.secrets = secrets; | ||
this.secretProvider = secretProvider; | ||
} | ||
|
||
getSecret(name: string): Promise<SecretValue> { | ||
return this.secretProvider.get(this.env, name); | ||
} | ||
|
||
getSecretPrefix(prefix: string): Promise<SecretValue[]> { | ||
return this.secretProvider.getPrefix(this.env, prefix); | ||
} | ||
} | ||
|
||
export const Finder = { | ||
optinal<T>( | ||
obj: any, | ||
paths: string[], | ||
defaultValue?: T, | ||
): T | undefined { | ||
let current = obj; | ||
for (const p of paths) { | ||
const val = current[p]; | ||
if (val === undefined || val === null) { | ||
return (defaultValue === undefined) ? undefined : defaultValue; | ||
} | ||
current = val; | ||
} | ||
return current as T; | ||
}, | ||
|
||
required<T>( | ||
obj: any, | ||
paths: string[], | ||
defaultValue?: T, | ||
): T { | ||
const res = this.optinal(obj, paths, defaultValue); | ||
if (res === undefined) { | ||
throw new Error(`cannot find value for paths ${paths.join(".")}`); | ||
} | ||
return res!; | ||
}, | ||
|
||
optionalString(obj: any, paths: string[], defaultValue?: string) { | ||
return this.optinal<string>(obj, paths, defaultValue); | ||
}, | ||
requiredString(obj: any, paths: string[], defaultValue?: string) { | ||
return this.required<string>(obj, paths, defaultValue); | ||
}, | ||
optionalNumber(obj: any, paths: string[], defaultValue?: number) { | ||
return this.optinal<number>(obj, paths, defaultValue); | ||
}, | ||
requiredNumber(obj: any, paths: string[], defaultValue?: number) { | ||
return this.required<number>(obj, paths, defaultValue); | ||
}, | ||
optionalBool(obj: any, paths: string[], defaultValue?: boolean) { | ||
return this.optinal<boolean>(obj, paths, defaultValue); | ||
}, | ||
requiredBool(obj: any, paths: string[], defaultValue?: boolean) { | ||
return this.required<boolean>(obj, paths, defaultValue); | ||
}, | ||
|
||
getAsArray<K>(obj: any, paths: string[], defaultValue?: K[]) { | ||
const value = this.required(obj, paths, defaultValue); | ||
if (Array.isArray(value)) return value; | ||
return [value]; | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from "./infisical"; | ||
export * from "./static"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import InfisicalClient from "infisical-node"; | ||
import { SecretProvider } from "../context"; | ||
|
||
export class InfisicalSecretProvider implements SecretProvider { | ||
client: InfisicalClient; | ||
|
||
constructor(siteURL: string, token: string, debug: boolean = false) { | ||
this.client = new InfisicalClient({ | ||
token: token, | ||
siteURL: siteURL, | ||
debug: debug, | ||
}); | ||
} | ||
|
||
async get(env: string, name: string) { | ||
const parts = name.split("/"); | ||
const [secretName, ...paths] = parts.reverse(); | ||
const secret = await this.client.getSecret(secretName, { | ||
environment: env, | ||
path: `/${paths.reverse().join("/")}`, | ||
type: "shared", | ||
}); | ||
return { | ||
name: name, | ||
value: secret.secretValue, | ||
}; | ||
} | ||
|
||
async getPrefix(env: string, prefix: string) { | ||
const secrets = await this.client.getAllSecrets({ | ||
environment: env, | ||
path: `/${prefix}`, | ||
attachToProcessEnv: false, | ||
includeImports: false, | ||
}); | ||
return secrets.map((s) => ({ | ||
name: s.secretName, | ||
value: s.secretValue, | ||
})); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Finder, SecretProvider, SecretValue } from "../context"; | ||
|
||
export class StaticSecretProvider implements SecretProvider { | ||
secrets: any; | ||
|
||
constructor(secrets: any) { | ||
this.secrets = secrets; | ||
} | ||
|
||
get(_: string, name: string): Promise<SecretValue> { | ||
const paths = name.split("/"); | ||
const secretName = paths[paths.length - 1]; | ||
const value = Finder.optinal<string>(this.secrets, paths); | ||
if (value !== undefined && typeof value !== "string") { | ||
throw new Error(`invalid secret value type of secret ${name}`); | ||
} | ||
return Promise.resolve({ name: secretName, value }); | ||
} | ||
|
||
getPrefix(_: string, prefix: string): Promise<SecretValue[]> { | ||
const paths = prefix.split("/"); | ||
const value = Finder.optinal<any>(this.secrets, paths); | ||
if (value === undefined) return Promise.resolve([]); | ||
const res: SecretValue[] = []; | ||
for (const [key, val] of Object.entries(value)) { | ||
res.push({ | ||
name: key, | ||
value: val as string, | ||
}); | ||
} | ||
return Promise.resolve(res); | ||
} | ||
} |