hanzio 1.0.10 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -4
- package/dist/api-wrapper/actions-impl.d.ts +4 -0
- package/dist/api-wrapper/builders.d.ts +23 -0
- package/dist/api-wrapper/create-client.d.ts +6 -0
- package/dist/api-wrapper/error-reporting.d.ts +7 -0
- package/dist/api-wrapper/errors.d.ts +64 -0
- package/dist/api-wrapper/headers.d.ts +10 -0
- package/dist/api-wrapper/index.d.ts +5 -84
- package/dist/api-wrapper/redaction.d.ts +2 -0
- package/dist/api-wrapper/shared.d.ts +16 -0
- package/dist/api-wrapper/size.d.ts +1 -0
- package/dist/api-wrapper/test-helpers.d.ts +6 -0
- package/dist/api-wrapper/transport.d.ts +55 -0
- package/dist/api-wrapper/types.d.ts +154 -0
- package/dist/api-wrapper/zod-issues.d.ts +17 -0
- package/dist/cache/index.d.ts +26 -0
- package/dist/secrets/core.d.ts +47 -0
- package/dist/secrets/deadline.d.ts +6 -0
- package/dist/secrets/environment.d.ts +9 -0
- package/dist/secrets/errors.d.ts +11 -0
- package/dist/secrets/index.d.ts +14 -23
- package/dist/secrets/infisical-cli.d.ts +6 -0
- package/dist/secrets/infisical-config.d.ts +17 -0
- package/dist/secrets/infisical-session.d.ts +4 -0
- package/dist/secrets/infisical.d.ts +14 -2
- package/dist/secrets/loaders.d.ts +9 -0
- package/dist/secrets/vite.d.ts +7 -3
- package/dist/secrets/worker-loader.d.ts +9 -0
- package/dist/secrets/worker.d.ts +3 -0
- package/dist/src/api-wrapper/index.js +1059 -177
- package/dist/src/index.js +2807 -1397
- package/dist/src/jwt/index.js +2 -2
- package/dist/src/p-queue/index.js +3 -3
- package/dist/src/secrets/index.js +1610 -407
- package/dist/src/secrets/infisical.js +1352 -214
- package/dist/src/secrets/loaders.js +1529 -0
- package/dist/src/secrets/vite.js +33 -11
- package/dist/src/secrets/worker.js +275 -0
- package/dist/src/sitemap/index.js +1 -1
- package/dist/src/zod/index.js +7 -7
- package/dist/typedswitch/index.d.ts +9 -5
- package/package.json +12 -3
- package/src/api-wrapper/actions-impl.ts +100 -0
- package/src/api-wrapper/builders.ts +200 -0
- package/src/api-wrapper/create-client.ts +393 -0
- package/src/api-wrapper/error-reporting.ts +31 -0
- package/src/api-wrapper/errors.ts +231 -0
- package/src/api-wrapper/headers.ts +79 -0
- package/src/api-wrapper/index.ts +5 -492
- package/src/api-wrapper/redaction.ts +62 -0
- package/src/api-wrapper/shared.ts +25 -0
- package/src/api-wrapper/size.ts +19 -0
- package/src/api-wrapper/test-helpers.ts +25 -0
- package/src/api-wrapper/transport.ts +350 -0
- package/src/api-wrapper/types.ts +259 -0
- package/src/api-wrapper/zod-issues.ts +157 -0
- package/src/cache/index.ts +228 -61
- package/src/secrets/core.ts +348 -0
- package/src/secrets/deadline.ts +69 -0
- package/src/secrets/environment.ts +69 -0
- package/src/secrets/errors.ts +29 -0
- package/src/secrets/index.ts +81 -140
- package/src/secrets/infisical-cli.ts +99 -0
- package/src/secrets/infisical-config.ts +70 -0
- package/src/secrets/infisical-session.ts +42 -0
- package/src/secrets/infisical.ts +219 -35
- package/src/secrets/loaders.ts +43 -0
- package/src/secrets/vite.ts +44 -15
- package/src/secrets/worker-loader.ts +56 -0
- package/src/secrets/worker.ts +4 -0
- package/src/typedswitch/index.ts +80 -69
package/src/secrets/index.ts
CHANGED
|
@@ -1,153 +1,94 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
readonly clientSecretEnvKey: string
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export type SecretSetLoader<SecretKey extends string> = (
|
|
28
|
-
context: SecretSetLoaderContext<SecretKey>
|
|
29
|
-
) => Promise<Partial<Record<SecretKey, string>>>
|
|
30
|
-
|
|
31
|
-
export type SecretSet<SecretKey extends string> = {
|
|
32
|
-
secret: (key: SecretKey) => string
|
|
33
|
-
secrets: () => Record<SecretKey, string>
|
|
34
|
-
reload: () => Promise<SecretSet<SecretKey>>
|
|
35
|
-
}
|
|
36
|
-
|
|
1
|
+
import {
|
|
2
|
+
defineSecretSet as defineCoreSecretSet,
|
|
3
|
+
type CommonSecretSetOptions,
|
|
4
|
+
type CustomLoaderDefineSecretSetOptions,
|
|
5
|
+
type SecretSet,
|
|
6
|
+
type SecretSetLoader
|
|
7
|
+
} from './core'
|
|
8
|
+
import {
|
|
9
|
+
getProcessEnvironment,
|
|
10
|
+
resolveSecretEnvironment,
|
|
11
|
+
type SecretEnvironment
|
|
12
|
+
} from './environment'
|
|
13
|
+
import {
|
|
14
|
+
DEFAULT_INFISICAL_SITE_URL,
|
|
15
|
+
loadInfisicalSecrets,
|
|
16
|
+
type InfisicalAuthMode
|
|
17
|
+
} from './infisical'
|
|
18
|
+
import {
|
|
19
|
+
validateInfisicalOrganizationId,
|
|
20
|
+
type InfisicalProjectOptions
|
|
21
|
+
} from './infisical-config'
|
|
22
|
+
|
|
23
|
+
export * from './core'
|
|
37
24
|
export * from './infisical'
|
|
25
|
+
export * from './loaders'
|
|
38
26
|
export * from './vite'
|
|
27
|
+
export type { SecretRequestOptions } from './deadline'
|
|
28
|
+
|
|
29
|
+
export type InfisicalDefineSecretSetOptions<
|
|
30
|
+
K extends string = string,
|
|
31
|
+
Parsed = Record<K, string>
|
|
32
|
+
> = CommonSecretSetOptions<K, Parsed> &
|
|
33
|
+
InfisicalProjectOptions & {
|
|
34
|
+
readonly auth?: InfisicalAuthMode
|
|
35
|
+
readonly clientIdEnvKey?: string
|
|
36
|
+
readonly clientSecretEnvKey?: string
|
|
37
|
+
readonly loader?: undefined
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type DefineSecretSetOptions<
|
|
41
|
+
K extends string,
|
|
42
|
+
Parsed = Record<K, string>
|
|
43
|
+
> =
|
|
44
|
+
| InfisicalDefineSecretSetOptions<K, Parsed>
|
|
45
|
+
| CustomLoaderDefineSecretSetOptions<K, Parsed>
|
|
39
46
|
|
|
40
47
|
export function getSecretEnvironment(): SecretEnvironment {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
return resolveSecretEnvironment(
|
|
49
|
+
undefined,
|
|
50
|
+
getProcessEnvironment()
|
|
51
|
+
) as SecretEnvironment
|
|
45
52
|
}
|
|
46
53
|
|
|
47
54
|
export async function defineSecretSet<
|
|
48
|
-
const
|
|
55
|
+
const Keys extends readonly string[],
|
|
56
|
+
Parsed = Record<Keys[number], string>
|
|
49
57
|
>(
|
|
50
|
-
keys:
|
|
51
|
-
options: DefineSecretSetOptions<
|
|
52
|
-
): Promise<SecretSet<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const keysMissingFromEnv = keySet.filter((key) => !envSecrets[key])
|
|
62
|
-
const environment = resolveEnvironment(options.environment)
|
|
63
|
-
|
|
64
|
-
logSecretEnvironment(environment, keySet.length)
|
|
65
|
-
|
|
66
|
-
const loadedSecrets: Partial<Record<SecretKey, string>> =
|
|
67
|
-
keysMissingFromEnv.length === 0 && !force
|
|
68
|
-
? {}
|
|
69
|
-
: await loader({
|
|
70
|
-
keys: keySet,
|
|
71
|
-
projectId: options.projectId,
|
|
72
|
-
environment,
|
|
73
|
-
siteUrl: options.siteUrl ?? DEFAULT_INFISICAL_SITE_URL,
|
|
74
|
-
clientIdEnvKey: options.clientIdEnvKey ?? 'INFISICAL_CLIENT_ID',
|
|
75
|
-
clientSecretEnvKey:
|
|
76
|
-
options.clientSecretEnvKey ?? 'INFISICAL_CLIENT_SECRET'
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
const missingKeys = keySet.filter(
|
|
80
|
-
(key) => !(envSecrets[key] ?? loadedSecrets[key])
|
|
81
|
-
)
|
|
82
|
-
if (missingKeys.length > 0) {
|
|
83
|
-
throw new Error(`Missing secrets: ${missingKeys.join(', ')}`)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const nextSecrets = Object.fromEntries(
|
|
87
|
-
keySet.map((key) => [
|
|
88
|
-
key,
|
|
89
|
-
(envSecrets[key] ?? loadedSecrets[key]) as string
|
|
90
|
-
])
|
|
91
|
-
) as Record<SecretKey, string>
|
|
92
|
-
|
|
93
|
-
for (const [key, value] of Object.entries(nextSecrets)) {
|
|
94
|
-
process.env[key] = value as string
|
|
95
|
-
}
|
|
96
|
-
cachedSecrets = nextSecrets
|
|
97
|
-
return nextSecrets
|
|
58
|
+
keys: Keys,
|
|
59
|
+
options: DefineSecretSetOptions<Keys[number], Parsed>
|
|
60
|
+
): Promise<SecretSet<Keys[number], Parsed>> {
|
|
61
|
+
let loader: SecretSetLoader<Keys[number]>
|
|
62
|
+
|
|
63
|
+
if (!options.loader) {
|
|
64
|
+
// Validate even when environment overrides satisfy every key.
|
|
65
|
+
validateInfisicalOrganizationId(options.organizationId)
|
|
66
|
+
loader = createDefaultInfisicalLoader(options)
|
|
67
|
+
} else {
|
|
68
|
+
loader = options.loader
|
|
98
69
|
}
|
|
99
70
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
return value
|
|
107
|
-
},
|
|
108
|
-
secrets() {
|
|
109
|
-
if (!cachedSecrets) {
|
|
110
|
-
throw new Error('Secrets not initialized.')
|
|
111
|
-
}
|
|
112
|
-
return cachedSecrets
|
|
113
|
-
},
|
|
114
|
-
async reload() {
|
|
115
|
-
await loadSecrets(true)
|
|
116
|
-
return secretSet
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
await loadSecrets()
|
|
121
|
-
return secretSet
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function resolveEnvironment(
|
|
125
|
-
environment: DefineSecretSetOptions<string>['environment']
|
|
126
|
-
): SecretEnvironment {
|
|
127
|
-
if (typeof environment === 'function') return environment()
|
|
128
|
-
return environment ?? getSecretEnvironment()
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function logSecretEnvironment(
|
|
132
|
-
environment: SecretEnvironment,
|
|
133
|
-
secretCount: number
|
|
134
|
-
): void {
|
|
135
|
-
logger.info(colorize('Loading secrets', 'cyan', 'bold'), {
|
|
136
|
-
environment: colorize(environment, 'brightCyan', 'bold'),
|
|
137
|
-
count: secretCount
|
|
138
|
-
})
|
|
71
|
+
// Supply process.env only from this Node/Bun entry point, keeping the core portable.
|
|
72
|
+
return defineCoreSecretSet(
|
|
73
|
+
keys,
|
|
74
|
+
{ ...options, loader },
|
|
75
|
+
getProcessEnvironment()
|
|
76
|
+
)
|
|
139
77
|
}
|
|
140
78
|
|
|
141
|
-
function
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
.
|
|
152
|
-
|
|
79
|
+
function createDefaultInfisicalLoader<K extends string, Parsed>(
|
|
80
|
+
options: InfisicalDefineSecretSetOptions<K, Parsed>
|
|
81
|
+
): SecretSetLoader<K> {
|
|
82
|
+
return (context) =>
|
|
83
|
+
loadInfisicalSecrets({
|
|
84
|
+
...context,
|
|
85
|
+
projectId: options.projectId,
|
|
86
|
+
organizationId: options.organizationId,
|
|
87
|
+
siteUrl: options.siteUrl ?? DEFAULT_INFISICAL_SITE_URL,
|
|
88
|
+
secretPath: options.secretPath,
|
|
89
|
+
auth: options.auth,
|
|
90
|
+
clientIdEnvKey: options.clientIdEnvKey ?? 'INFISICAL_CLIENT_ID',
|
|
91
|
+
clientSecretEnvKey:
|
|
92
|
+
options.clientSecretEnvKey ?? 'INFISICAL_CLIENT_SECRET'
|
|
93
|
+
})
|
|
153
94
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { SecretRequestOptions } from './deadline'
|
|
2
|
+
import { getProcessEnvironment } from './environment'
|
|
3
|
+
import { SecretLoadError } from './errors'
|
|
4
|
+
|
|
5
|
+
/** Read the active CLI session without a shell or credential-bearing errors. */
|
|
6
|
+
export async function readInfisicalCliToken(
|
|
7
|
+
options: SecretRequestOptions & { siteUrl: string; signal: AbortSignal }
|
|
8
|
+
): Promise<string> {
|
|
9
|
+
// Import subprocess support only when the CLI is actually selected.
|
|
10
|
+
const { execFile } = await import('node:child_process').catch(() => {
|
|
11
|
+
throw new SecretLoadError(
|
|
12
|
+
'CLI',
|
|
13
|
+
'Infisical CLI fallback requires a runtime with subprocess support. Provide Infisical client credentials or a custom secret loader.'
|
|
14
|
+
)
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
options.signal.throwIfAborted()
|
|
18
|
+
|
|
19
|
+
const env: Record<string, string | undefined> = {
|
|
20
|
+
...getProcessEnvironment(),
|
|
21
|
+
INFISICAL_DISABLE_UPDATE_CHECK: 'true'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Inherited machine tokens would override the CLI's signed-in user session.
|
|
25
|
+
// Remove them from the child copy without changing the parent's environment.
|
|
26
|
+
delete env.INFISICAL_TOKEN
|
|
27
|
+
delete env.INFISICAL_UNIVERSAL_AUTH_ACCESS_TOKEN
|
|
28
|
+
delete env.TOKEN
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const stdout = await new Promise<string>((resolve, reject) => {
|
|
32
|
+
const child = execFile(
|
|
33
|
+
'infisical',
|
|
34
|
+
[
|
|
35
|
+
'user',
|
|
36
|
+
'get',
|
|
37
|
+
'token',
|
|
38
|
+
'--plain',
|
|
39
|
+
`--domain=${options.siteUrl}`,
|
|
40
|
+
'--silent'
|
|
41
|
+
],
|
|
42
|
+
{
|
|
43
|
+
env,
|
|
44
|
+
encoding: 'utf8',
|
|
45
|
+
shell: false,
|
|
46
|
+
timeout: options.timeoutMs ?? 30_000,
|
|
47
|
+
signal: options.signal,
|
|
48
|
+
killSignal: 'SIGKILL',
|
|
49
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
50
|
+
windowsHide: true
|
|
51
|
+
},
|
|
52
|
+
(error, output) => {
|
|
53
|
+
if (error) {
|
|
54
|
+
reject(error)
|
|
55
|
+
} else {
|
|
56
|
+
resolve(output)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
// Startup cannot wait for interactive input.
|
|
62
|
+
child.stdin?.end()
|
|
63
|
+
})
|
|
64
|
+
return stdout.trim()
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (options.signal.aborted) {
|
|
67
|
+
throw options.signal.reason
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Subprocess errors can contain secret stdout/stderr, so rebuild the error.
|
|
71
|
+
const failure = error as { code?: string | number; killed?: boolean } | null
|
|
72
|
+
|
|
73
|
+
if (failure?.code === 'ENOENT') {
|
|
74
|
+
throw new SecretLoadError(
|
|
75
|
+
'CLI',
|
|
76
|
+
'Infisical CLI not found. Install infisical and ensure it is on PATH, or provide Infisical client credentials.'
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (failure?.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') {
|
|
81
|
+
throw new SecretLoadError(
|
|
82
|
+
'CLI',
|
|
83
|
+
'Infisical CLI output exceeded the 10 MiB limit.'
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (failure?.killed) {
|
|
88
|
+
throw new SecretLoadError(
|
|
89
|
+
'TIMEOUT',
|
|
90
|
+
`Infisical CLI timed out after ${(options.timeoutMs ?? 30_000) / 1000} seconds or was terminated.`
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
throw new SecretLoadError(
|
|
95
|
+
'CLI',
|
|
96
|
+
`Infisical CLI session token failed. Run infisical login --domain=${options.siteUrl} and verify access to the configured organization, project, and environment.`
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { SecretRequestOptions } from './deadline'
|
|
2
|
+
import { SecretLoadError } from './errors'
|
|
3
|
+
|
|
4
|
+
/** Project scope shared by the public Infisical loaders. */
|
|
5
|
+
export type InfisicalProjectOptions = {
|
|
6
|
+
readonly projectId: string
|
|
7
|
+
|
|
8
|
+
/** Scope CLI user authentication; machine identities already have an organization. */
|
|
9
|
+
readonly organizationId: string
|
|
10
|
+
readonly siteUrl?: string
|
|
11
|
+
readonly secretPath?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type InfisicalScope<K extends string> = InfisicalProjectOptions &
|
|
15
|
+
SecretRequestOptions & {
|
|
16
|
+
readonly keys: readonly K[]
|
|
17
|
+
readonly environment: string
|
|
18
|
+
readonly siteUrl: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function validateInfisicalScope(options: InfisicalScope<string>): void {
|
|
22
|
+
validateInfisicalOrganizationId(options.organizationId)
|
|
23
|
+
|
|
24
|
+
let url: URL
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
url = new URL(options.siteUrl)
|
|
28
|
+
} catch {
|
|
29
|
+
throw new SecretLoadError('CONFIGURATION', 'Invalid Infisical siteUrl.')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Keep credentials and other sensitive URL components out of diagnostics.
|
|
33
|
+
if (
|
|
34
|
+
!['http:', 'https:'].includes(url.protocol) ||
|
|
35
|
+
url.username ||
|
|
36
|
+
url.password ||
|
|
37
|
+
url.search ||
|
|
38
|
+
url.hash
|
|
39
|
+
) {
|
|
40
|
+
throw new SecretLoadError(
|
|
41
|
+
'CONFIGURATION',
|
|
42
|
+
'Infisical siteUrl must be an HTTP(S) URL without credentials, query, or fragment.'
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
!options.projectId.trim() ||
|
|
48
|
+
!options.environment.trim() ||
|
|
49
|
+
!(options.secretPath ?? '/').startsWith('/')
|
|
50
|
+
) {
|
|
51
|
+
throw new SecretLoadError(
|
|
52
|
+
'CONFIGURATION',
|
|
53
|
+
'Infisical requires a projectId, environment, and absolute secretPath.'
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Validate at configuration time, including for JavaScript callers and local-only loads. */
|
|
59
|
+
export function validateInfisicalOrganizationId(organizationId: unknown): void {
|
|
60
|
+
if (
|
|
61
|
+
typeof organizationId !== 'string' ||
|
|
62
|
+
!organizationId.trim() ||
|
|
63
|
+
/\s/.test(organizationId)
|
|
64
|
+
) {
|
|
65
|
+
throw new SecretLoadError(
|
|
66
|
+
'CONFIGURATION',
|
|
67
|
+
'Infisical organizationId is required and must be a nonempty ID without whitespace.'
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { SecretLoadError } from './errors'
|
|
3
|
+
|
|
4
|
+
const sessionClaimsSchema = z.object({
|
|
5
|
+
organizationId: z.string().optional(),
|
|
6
|
+
subOrganizationId: z.string().optional(),
|
|
7
|
+
exp: z.number().finite().optional()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
/** Read routing metadata only. JWT signature and permissions are verified by Infisical. */
|
|
11
|
+
export function parseInfisicalSessionToken(token: string): {
|
|
12
|
+
organizationId?: string
|
|
13
|
+
} {
|
|
14
|
+
let claims: z.infer<typeof sessionClaimsSchema>
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Reject empty, formatted, or multiline CLI output before making an HTTP request.
|
|
18
|
+
if (!/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(token)) {
|
|
19
|
+
throw new Error('Invalid token format')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const payload = token.split('.')[1]!
|
|
23
|
+
const json = atob(payload.replace(/-/g, '+').replace(/_/g, '/'))
|
|
24
|
+
|
|
25
|
+
claims = sessionClaimsSchema.parse(JSON.parse(json))
|
|
26
|
+
} catch {
|
|
27
|
+
throw new SecretLoadError(
|
|
28
|
+
'AUTHENTICATION',
|
|
29
|
+
'Infisical returned an invalid user session token. Run infisical login for the configured domain.'
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (claims.exp !== undefined && claims.exp <= Date.now() / 1000) {
|
|
34
|
+
throw new SecretLoadError(
|
|
35
|
+
'AUTHENTICATION',
|
|
36
|
+
'Infisical user session has expired. Run infisical login for the configured domain.'
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// For sub-organizations, the root organization claim does not identify the scope.
|
|
41
|
+
return { organizationId: claims.subOrganizationId ?? claims.organizationId }
|
|
42
|
+
}
|