@karmaniverous/get-dotenv 6.2.3 → 6.3.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 +1 -0
- package/dist/chunks/AwsRestJsonProtocol-Dv5q8CFK.mjs +932 -0
- package/dist/chunks/createCli-BSn6Be40.mjs +440 -0
- package/dist/chunks/externalDataInterceptor-pqHO-Qmn.mjs +19 -0
- package/dist/chunks/getSSOTokenFromFile-otmZHSRV.mjs +22 -0
- package/dist/chunks/helpConfig-CGejgwWW.mjs +12 -0
- package/dist/chunks/index-B18W-ELX.mjs +273 -0
- package/dist/chunks/index-BNcKuiBy.mjs +9375 -0
- package/dist/chunks/index-Bi0RIILn.mjs +25 -0
- package/dist/chunks/index-BqZ3PB6c.mjs +375 -0
- package/dist/chunks/index-C4Ac6feq.mjs +355 -0
- package/dist/chunks/index-C6uLiKpC.mjs +703 -0
- package/dist/chunks/index-CGg5wWCm.mjs +188 -0
- package/dist/chunks/index-CXpZ0pei.mjs +579 -0
- package/dist/chunks/index-CYoFYXZv.mjs +103 -0
- package/dist/chunks/index-DFNcs3pR.mjs +444 -0
- package/dist/chunks/index-DLQEHTw4.mjs +83 -0
- package/dist/chunks/index-DtRaL61T.mjs +380 -0
- package/dist/chunks/index-eZMlmESW.mjs +522 -0
- package/dist/chunks/invoke-DuRPU1oC.mjs +60 -0
- package/dist/chunks/loadModuleDefault-Dj8B3Stt.mjs +123 -0
- package/dist/chunks/loadSso-CJ_XUhEj.mjs +413 -0
- package/dist/chunks/loader-CePOf74i.mjs +347 -0
- package/dist/chunks/overlayEnv-Bqh_kPGA.mjs +235 -0
- package/dist/chunks/package-boo9EyYs.mjs +5 -0
- package/dist/chunks/parseKnownFiles-B6x1cUmR.mjs +23 -0
- package/dist/chunks/readMergedOptions-DLBDzpXX.mjs +1627 -0
- package/dist/chunks/resolveCliOptions-_qtsVxda.mjs +139 -0
- package/dist/chunks/sdk-stream-mixin-DCdC70Up.mjs +167 -0
- package/dist/chunks/spawnEnv-CQwFu7ZJ.mjs +307 -0
- package/dist/chunks/types-DdqcXCV1.mjs +59 -0
- package/dist/chunks/validate-CDl0rE6k.mjs +61 -0
- package/dist/cli.mjs +39 -19307
- package/dist/cliHost.mjs +21 -2800
- package/dist/config.mjs +11 -509
- package/dist/env-overlay.mjs +7 -337
- package/dist/getdotenv.cli.mjs +39 -19305
- package/dist/index.d.ts +485 -2
- package/dist/index.mjs +657 -19322
- package/dist/plugins-aws.d.ts +1 -4
- package/dist/plugins-aws.mjs +66 -2568
- package/dist/plugins-batch.mjs +17 -2573
- package/dist/plugins-cmd.mjs +20 -3094
- package/dist/plugins-init.d.ts +8 -0
- package/dist/plugins-init.mjs +85 -2297
- package/dist/plugins.mjs +36 -18817
- package/package.json +1 -2
- package/dist/templates/cli/index.ts +0 -25
- package/dist/templates/cli/plugins/hello/defaultAction.ts +0 -27
- package/dist/templates/cli/plugins/hello/index.ts +0 -26
- package/dist/templates/cli/plugins/hello/options.ts +0 -31
- package/dist/templates/cli/plugins/hello/strangerAction.ts +0 -20
- package/dist/templates/cli/plugins/hello/types.ts +0 -13
- package/dist/templates/config/js/getdotenv.config.js +0 -20
- package/dist/templates/config/json/local/getdotenv.config.local.json +0 -7
- package/dist/templates/config/json/public/getdotenv.config.json +0 -9
- package/dist/templates/config/public/getdotenv.config.json +0 -8
- package/dist/templates/config/ts/getdotenv.config.ts +0 -28
- package/dist/templates/config/yaml/local/getdotenv.config.local.yaml +0 -7
- package/dist/templates/config/yaml/public/getdotenv.config.yaml +0 -7
- package/dist/templates/defaultAction.ts +0 -27
- package/dist/templates/getdotenv.config.js +0 -20
- package/dist/templates/getdotenv.config.json +0 -9
- package/dist/templates/getdotenv.config.local.json +0 -7
- package/dist/templates/getdotenv.config.local.yaml +0 -7
- package/dist/templates/getdotenv.config.ts +0 -28
- package/dist/templates/getdotenv.config.yaml +0 -7
- package/dist/templates/hello/defaultAction.ts +0 -27
- package/dist/templates/hello/index.ts +0 -26
- package/dist/templates/hello/options.ts +0 -31
- package/dist/templates/hello/strangerAction.ts +0 -20
- package/dist/templates/hello/types.ts +0 -13
- package/dist/templates/index.ts +0 -26
- package/dist/templates/js/getdotenv.config.js +0 -20
- package/dist/templates/json/local/getdotenv.config.local.json +0 -7
- package/dist/templates/json/public/getdotenv.config.json +0 -9
- package/dist/templates/local/getdotenv.config.local.json +0 -7
- package/dist/templates/local/getdotenv.config.local.yaml +0 -7
- package/dist/templates/options.ts +0 -31
- package/dist/templates/plugins/hello/defaultAction.ts +0 -27
- package/dist/templates/plugins/hello/index.ts +0 -26
- package/dist/templates/plugins/hello/options.ts +0 -31
- package/dist/templates/plugins/hello/strangerAction.ts +0 -20
- package/dist/templates/plugins/hello/types.ts +0 -13
- package/dist/templates/public/getdotenv.config.json +0 -9
- package/dist/templates/public/getdotenv.config.yaml +0 -7
- package/dist/templates/strangerAction.ts +0 -20
- package/dist/templates/ts/getdotenv.config.ts +0 -28
- package/dist/templates/types.ts +0 -13
- package/dist/templates/yaml/local/getdotenv.config.local.yaml +0 -7
- package/dist/templates/yaml/public/getdotenv.config.yaml +0 -7
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
import { C as CredentialsProviderError, s as setCredentialFeature, u as chain, k as getProfileName, v as readFile, H as HttpRequest } from './index-BNcKuiBy.mjs';
|
|
2
|
+
import { createHash, createPrivateKey, createPublicKey, sign } from 'node:crypto';
|
|
3
|
+
import { promises } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { p as parseKnownFiles } from './parseKnownFiles-B6x1cUmR.mjs';
|
|
7
|
+
import './readMergedOptions-DLBDzpXX.mjs';
|
|
8
|
+
import 'zod';
|
|
9
|
+
import '@commander-js/extra-typings';
|
|
10
|
+
import './overlayEnv-Bqh_kPGA.mjs';
|
|
11
|
+
import 'fs-extra';
|
|
12
|
+
import './loadModuleDefault-Dj8B3Stt.mjs';
|
|
13
|
+
import 'crypto';
|
|
14
|
+
import 'path';
|
|
15
|
+
import 'url';
|
|
16
|
+
import 'nanoid';
|
|
17
|
+
import 'dotenv';
|
|
18
|
+
import './loader-CePOf74i.mjs';
|
|
19
|
+
import 'package-directory';
|
|
20
|
+
import 'yaml';
|
|
21
|
+
import 'execa';
|
|
22
|
+
import 'buffer';
|
|
23
|
+
import 'os';
|
|
24
|
+
import 'node:fs/promises';
|
|
25
|
+
import 'http';
|
|
26
|
+
import 'https';
|
|
27
|
+
import 'stream';
|
|
28
|
+
import 'process';
|
|
29
|
+
|
|
30
|
+
const resolveCredentialSource = (credentialSource, profileName, logger) => {
|
|
31
|
+
const sourceProvidersMap = {
|
|
32
|
+
EcsContainer: async (options) => {
|
|
33
|
+
const { fromHttp } = await import('./index-CGg5wWCm.mjs');
|
|
34
|
+
const { fromContainerMetadata } = await import('./index-DtRaL61T.mjs');
|
|
35
|
+
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is EcsContainer");
|
|
36
|
+
return async () => chain(fromHttp(options ?? {}), fromContainerMetadata(options))().then(setNamedProvider);
|
|
37
|
+
},
|
|
38
|
+
Ec2InstanceMetadata: async (options) => {
|
|
39
|
+
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is Ec2InstanceMetadata");
|
|
40
|
+
const { fromInstanceMetadata } = await import('./index-DtRaL61T.mjs');
|
|
41
|
+
return async () => fromInstanceMetadata(options)().then(setNamedProvider);
|
|
42
|
+
},
|
|
43
|
+
Environment: async (options) => {
|
|
44
|
+
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is Environment");
|
|
45
|
+
const { fromEnv } = await import('./index-Bi0RIILn.mjs');
|
|
46
|
+
return async () => fromEnv(options)().then(setNamedProvider);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
if (credentialSource in sourceProvidersMap) {
|
|
50
|
+
return sourceProvidersMap[credentialSource];
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
throw new CredentialsProviderError(`Unsupported credential source in profile ${profileName}. Got ${credentialSource}, ` +
|
|
54
|
+
`expected EcsContainer or Ec2InstanceMetadata or Environment.`, { logger });
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const setNamedProvider = (creds) => setCredentialFeature(creds, "CREDENTIALS_PROFILE_NAMED_PROVIDER", "p");
|
|
58
|
+
|
|
59
|
+
const isAssumeRoleProfile = (arg, { profile = "default", logger } = {}) => {
|
|
60
|
+
return (Boolean(arg) &&
|
|
61
|
+
typeof arg === "object" &&
|
|
62
|
+
typeof arg.role_arn === "string" &&
|
|
63
|
+
["undefined", "string"].indexOf(typeof arg.role_session_name) > -1 &&
|
|
64
|
+
["undefined", "string"].indexOf(typeof arg.external_id) > -1 &&
|
|
65
|
+
["undefined", "string"].indexOf(typeof arg.mfa_serial) > -1 &&
|
|
66
|
+
(isAssumeRoleWithSourceProfile(arg, { profile, logger }) || isCredentialSourceProfile(arg, { profile, logger })));
|
|
67
|
+
};
|
|
68
|
+
const isAssumeRoleWithSourceProfile = (arg, { profile, logger }) => {
|
|
69
|
+
const withSourceProfile = typeof arg.source_profile === "string" && typeof arg.credential_source === "undefined";
|
|
70
|
+
if (withSourceProfile) {
|
|
71
|
+
logger?.debug?.(` ${profile} isAssumeRoleWithSourceProfile source_profile=${arg.source_profile}`);
|
|
72
|
+
}
|
|
73
|
+
return withSourceProfile;
|
|
74
|
+
};
|
|
75
|
+
const isCredentialSourceProfile = (arg, { profile, logger }) => {
|
|
76
|
+
const withProviderProfile = typeof arg.credential_source === "string" && typeof arg.source_profile === "undefined";
|
|
77
|
+
if (withProviderProfile) {
|
|
78
|
+
logger?.debug?.(` ${profile} isCredentialSourceProfile credential_source=${arg.credential_source}`);
|
|
79
|
+
}
|
|
80
|
+
return withProviderProfile;
|
|
81
|
+
};
|
|
82
|
+
const resolveAssumeRoleCredentials = async (profileName, profiles, options, visitedProfiles = {}, resolveProfileData) => {
|
|
83
|
+
options.logger?.debug("@aws-sdk/credential-provider-ini - resolveAssumeRoleCredentials (STS)");
|
|
84
|
+
const profileData = profiles[profileName];
|
|
85
|
+
const { source_profile, region } = profileData;
|
|
86
|
+
if (!options.roleAssumer) {
|
|
87
|
+
const { getDefaultRoleAssumer } = await import('./index-C6uLiKpC.mjs');
|
|
88
|
+
options.roleAssumer = getDefaultRoleAssumer({
|
|
89
|
+
...options.clientConfig,
|
|
90
|
+
credentialProviderLogger: options.logger,
|
|
91
|
+
parentClientConfig: {
|
|
92
|
+
...options?.parentClientConfig,
|
|
93
|
+
region: region ?? options?.parentClientConfig?.region,
|
|
94
|
+
},
|
|
95
|
+
}, options.clientPlugins);
|
|
96
|
+
}
|
|
97
|
+
if (source_profile && source_profile in visitedProfiles) {
|
|
98
|
+
throw new CredentialsProviderError(`Detected a cycle attempting to resolve credentials for profile` +
|
|
99
|
+
` ${getProfileName(options)}. Profiles visited: ` +
|
|
100
|
+
Object.keys(visitedProfiles).join(", "), { logger: options.logger });
|
|
101
|
+
}
|
|
102
|
+
options.logger?.debug(`@aws-sdk/credential-provider-ini - finding credential resolver using ${source_profile ? `source_profile=[${source_profile}]` : `profile=[${profileName}]`}`);
|
|
103
|
+
const sourceCredsProvider = source_profile
|
|
104
|
+
? resolveProfileData(source_profile, profiles, options, {
|
|
105
|
+
...visitedProfiles,
|
|
106
|
+
[source_profile]: true,
|
|
107
|
+
}, isCredentialSourceWithoutRoleArn(profiles[source_profile] ?? {}))
|
|
108
|
+
: (await resolveCredentialSource(profileData.credential_source, profileName, options.logger)(options))();
|
|
109
|
+
if (isCredentialSourceWithoutRoleArn(profileData)) {
|
|
110
|
+
return sourceCredsProvider.then((creds) => setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
const params = {
|
|
114
|
+
RoleArn: profileData.role_arn,
|
|
115
|
+
RoleSessionName: profileData.role_session_name || `aws-sdk-js-${Date.now()}`,
|
|
116
|
+
ExternalId: profileData.external_id,
|
|
117
|
+
DurationSeconds: parseInt(profileData.duration_seconds || "3600", 10),
|
|
118
|
+
};
|
|
119
|
+
const { mfa_serial } = profileData;
|
|
120
|
+
if (mfa_serial) {
|
|
121
|
+
if (!options.mfaCodeProvider) {
|
|
122
|
+
throw new CredentialsProviderError(`Profile ${profileName} requires multi-factor authentication, but no MFA code callback was provided.`, { logger: options.logger, tryNextLink: false });
|
|
123
|
+
}
|
|
124
|
+
params.SerialNumber = mfa_serial;
|
|
125
|
+
params.TokenCode = await options.mfaCodeProvider(mfa_serial);
|
|
126
|
+
}
|
|
127
|
+
const sourceCreds = await sourceCredsProvider;
|
|
128
|
+
return options.roleAssumer(sourceCreds, params).then((creds) => setCredentialFeature(creds, "CREDENTIALS_PROFILE_SOURCE_PROFILE", "o"));
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
const isCredentialSourceWithoutRoleArn = (section) => {
|
|
132
|
+
return !section.role_arn && !!section.credential_source;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
class LoginCredentialsFetcher {
|
|
136
|
+
profileData;
|
|
137
|
+
init;
|
|
138
|
+
callerClientConfig;
|
|
139
|
+
static REFRESH_THRESHOLD = 5 * 60 * 1000;
|
|
140
|
+
constructor(profileData, init, callerClientConfig) {
|
|
141
|
+
this.profileData = profileData;
|
|
142
|
+
this.init = init;
|
|
143
|
+
this.callerClientConfig = callerClientConfig;
|
|
144
|
+
}
|
|
145
|
+
async loadCredentials() {
|
|
146
|
+
const token = await this.loadToken();
|
|
147
|
+
if (!token) {
|
|
148
|
+
throw new CredentialsProviderError(`Failed to load a token for session ${this.loginSession}, please re-authenticate using aws login`, { tryNextLink: false, logger: this.logger });
|
|
149
|
+
}
|
|
150
|
+
const accessToken = token.accessToken;
|
|
151
|
+
const now = Date.now();
|
|
152
|
+
const expiryTime = new Date(accessToken.expiresAt).getTime();
|
|
153
|
+
const timeUntilExpiry = expiryTime - now;
|
|
154
|
+
if (timeUntilExpiry <= LoginCredentialsFetcher.REFRESH_THRESHOLD) {
|
|
155
|
+
return this.refresh(token);
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
accessKeyId: accessToken.accessKeyId,
|
|
159
|
+
secretAccessKey: accessToken.secretAccessKey,
|
|
160
|
+
sessionToken: accessToken.sessionToken,
|
|
161
|
+
accountId: accessToken.accountId,
|
|
162
|
+
expiration: new Date(accessToken.expiresAt),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
get logger() {
|
|
166
|
+
return this.init?.logger;
|
|
167
|
+
}
|
|
168
|
+
get loginSession() {
|
|
169
|
+
return this.profileData.login_session;
|
|
170
|
+
}
|
|
171
|
+
async refresh(token) {
|
|
172
|
+
const { SigninClient, CreateOAuth2TokenCommand } = await import('./index-DFNcs3pR.mjs');
|
|
173
|
+
const { logger, userAgentAppId } = this.callerClientConfig ?? {};
|
|
174
|
+
const isH2 = (requestHandler) => {
|
|
175
|
+
return requestHandler?.metadata?.handlerProtocol === "h2";
|
|
176
|
+
};
|
|
177
|
+
const requestHandler = isH2(this.callerClientConfig?.requestHandler)
|
|
178
|
+
? undefined
|
|
179
|
+
: this.callerClientConfig?.requestHandler;
|
|
180
|
+
const region = this.profileData.region ?? (await this.callerClientConfig?.region?.()) ?? process.env.AWS_REGION;
|
|
181
|
+
const client = new SigninClient({
|
|
182
|
+
credentials: {
|
|
183
|
+
accessKeyId: "",
|
|
184
|
+
secretAccessKey: "",
|
|
185
|
+
},
|
|
186
|
+
region,
|
|
187
|
+
requestHandler,
|
|
188
|
+
logger,
|
|
189
|
+
userAgentAppId,
|
|
190
|
+
...this.init?.clientConfig,
|
|
191
|
+
});
|
|
192
|
+
this.createDPoPInterceptor(client.middlewareStack);
|
|
193
|
+
const commandInput = {
|
|
194
|
+
tokenInput: {
|
|
195
|
+
clientId: token.clientId,
|
|
196
|
+
refreshToken: token.refreshToken,
|
|
197
|
+
grantType: "refresh_token",
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
try {
|
|
201
|
+
const response = await client.send(new CreateOAuth2TokenCommand(commandInput));
|
|
202
|
+
const { accessKeyId, secretAccessKey, sessionToken } = response.tokenOutput?.accessToken ?? {};
|
|
203
|
+
const { refreshToken, expiresIn } = response.tokenOutput ?? {};
|
|
204
|
+
if (!accessKeyId || !secretAccessKey || !sessionToken || !refreshToken) {
|
|
205
|
+
throw new CredentialsProviderError("Token refresh response missing required fields", {
|
|
206
|
+
logger: this.logger,
|
|
207
|
+
tryNextLink: false,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
const expiresInMs = (expiresIn ?? 900) * 1000;
|
|
211
|
+
const expiration = new Date(Date.now() + expiresInMs);
|
|
212
|
+
const updatedToken = {
|
|
213
|
+
...token,
|
|
214
|
+
accessToken: {
|
|
215
|
+
...token.accessToken,
|
|
216
|
+
accessKeyId: accessKeyId,
|
|
217
|
+
secretAccessKey: secretAccessKey,
|
|
218
|
+
sessionToken: sessionToken,
|
|
219
|
+
expiresAt: expiration.toISOString(),
|
|
220
|
+
},
|
|
221
|
+
refreshToken: refreshToken,
|
|
222
|
+
};
|
|
223
|
+
await this.saveToken(updatedToken);
|
|
224
|
+
const newAccessToken = updatedToken.accessToken;
|
|
225
|
+
return {
|
|
226
|
+
accessKeyId: newAccessToken.accessKeyId,
|
|
227
|
+
secretAccessKey: newAccessToken.secretAccessKey,
|
|
228
|
+
sessionToken: newAccessToken.sessionToken,
|
|
229
|
+
accountId: newAccessToken.accountId,
|
|
230
|
+
expiration,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
if (error.name === "AccessDeniedException") {
|
|
235
|
+
const errorType = error.error;
|
|
236
|
+
let message;
|
|
237
|
+
switch (errorType) {
|
|
238
|
+
case "TOKEN_EXPIRED":
|
|
239
|
+
message = "Your session has expired. Please reauthenticate.";
|
|
240
|
+
break;
|
|
241
|
+
case "USER_CREDENTIALS_CHANGED":
|
|
242
|
+
message =
|
|
243
|
+
"Unable to refresh credentials because of a change in your password. Please reauthenticate with your new password.";
|
|
244
|
+
break;
|
|
245
|
+
case "INSUFFICIENT_PERMISSIONS":
|
|
246
|
+
message =
|
|
247
|
+
"Unable to refresh credentials due to insufficient permissions. You may be missing permission for the 'CreateOAuth2Token' action.";
|
|
248
|
+
break;
|
|
249
|
+
default:
|
|
250
|
+
message = `Failed to refresh token: ${String(error)}. Please re-authenticate using \`aws login\``;
|
|
251
|
+
}
|
|
252
|
+
throw new CredentialsProviderError(message, { logger: this.logger, tryNextLink: false });
|
|
253
|
+
}
|
|
254
|
+
throw new CredentialsProviderError(`Failed to refresh token: ${String(error)}. Please re-authenticate using aws login`, { logger: this.logger });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async loadToken() {
|
|
258
|
+
const tokenFilePath = this.getTokenFilePath();
|
|
259
|
+
try {
|
|
260
|
+
let tokenData;
|
|
261
|
+
try {
|
|
262
|
+
tokenData = await readFile(tokenFilePath, { ignoreCache: this.init?.ignoreCache });
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
tokenData = await promises.readFile(tokenFilePath, "utf8");
|
|
266
|
+
}
|
|
267
|
+
const token = JSON.parse(tokenData);
|
|
268
|
+
const missingFields = ["accessToken", "clientId", "refreshToken", "dpopKey"].filter((k) => !token[k]);
|
|
269
|
+
if (!token.accessToken?.accountId) {
|
|
270
|
+
missingFields.push("accountId");
|
|
271
|
+
}
|
|
272
|
+
if (missingFields.length > 0) {
|
|
273
|
+
throw new CredentialsProviderError(`Token validation failed, missing fields: ${missingFields.join(", ")}`, {
|
|
274
|
+
logger: this.logger,
|
|
275
|
+
tryNextLink: false,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
return token;
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
281
|
+
throw new CredentialsProviderError(`Failed to load token from ${tokenFilePath}: ${String(error)}`, {
|
|
282
|
+
logger: this.logger,
|
|
283
|
+
tryNextLink: false,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async saveToken(token) {
|
|
288
|
+
const tokenFilePath = this.getTokenFilePath();
|
|
289
|
+
const directory = dirname(tokenFilePath);
|
|
290
|
+
try {
|
|
291
|
+
await promises.mkdir(directory, { recursive: true });
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
}
|
|
295
|
+
await promises.writeFile(tokenFilePath, JSON.stringify(token, null, 2), "utf8");
|
|
296
|
+
}
|
|
297
|
+
getTokenFilePath() {
|
|
298
|
+
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? join(homedir(), ".aws", "login", "cache");
|
|
299
|
+
const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
|
|
300
|
+
const loginSessionSha256 = createHash("sha256").update(loginSessionBytes).digest("hex");
|
|
301
|
+
return join(directory, `${loginSessionSha256}.json`);
|
|
302
|
+
}
|
|
303
|
+
derToRawSignature(derSignature) {
|
|
304
|
+
let offset = 2;
|
|
305
|
+
if (derSignature[offset] !== 0x02) {
|
|
306
|
+
throw new Error("Invalid DER signature");
|
|
307
|
+
}
|
|
308
|
+
offset++;
|
|
309
|
+
const rLength = derSignature[offset++];
|
|
310
|
+
let r = derSignature.subarray(offset, offset + rLength);
|
|
311
|
+
offset += rLength;
|
|
312
|
+
if (derSignature[offset] !== 0x02) {
|
|
313
|
+
throw new Error("Invalid DER signature");
|
|
314
|
+
}
|
|
315
|
+
offset++;
|
|
316
|
+
const sLength = derSignature[offset++];
|
|
317
|
+
let s = derSignature.subarray(offset, offset + sLength);
|
|
318
|
+
r = r[0] === 0x00 ? r.subarray(1) : r;
|
|
319
|
+
s = s[0] === 0x00 ? s.subarray(1) : s;
|
|
320
|
+
const rPadded = Buffer.concat([Buffer.alloc(32 - r.length), r]);
|
|
321
|
+
const sPadded = Buffer.concat([Buffer.alloc(32 - s.length), s]);
|
|
322
|
+
return Buffer.concat([rPadded, sPadded]);
|
|
323
|
+
}
|
|
324
|
+
createDPoPInterceptor(middlewareStack) {
|
|
325
|
+
middlewareStack.add((next) => async (args) => {
|
|
326
|
+
if (HttpRequest.isInstance(args.request)) {
|
|
327
|
+
const request = args.request;
|
|
328
|
+
const actualEndpoint = `${request.protocol}//${request.hostname}${request.port ? `:${request.port}` : ""}${request.path}`;
|
|
329
|
+
const dpop = await this.generateDpop(request.method, actualEndpoint);
|
|
330
|
+
request.headers = {
|
|
331
|
+
...request.headers,
|
|
332
|
+
DPoP: dpop,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
return next(args);
|
|
336
|
+
}, {
|
|
337
|
+
step: "finalizeRequest",
|
|
338
|
+
name: "dpopInterceptor",
|
|
339
|
+
override: true,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
async generateDpop(method = "POST", endpoint) {
|
|
343
|
+
const token = await this.loadToken();
|
|
344
|
+
try {
|
|
345
|
+
const privateKey = createPrivateKey({
|
|
346
|
+
key: token.dpopKey,
|
|
347
|
+
format: "pem",
|
|
348
|
+
type: "sec1",
|
|
349
|
+
});
|
|
350
|
+
const publicKey = createPublicKey(privateKey);
|
|
351
|
+
const publicDer = publicKey.export({ format: "der", type: "spki" });
|
|
352
|
+
let pointStart = -1;
|
|
353
|
+
for (let i = 0; i < publicDer.length; i++) {
|
|
354
|
+
if (publicDer[i] === 0x04) {
|
|
355
|
+
pointStart = i;
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
const x = publicDer.slice(pointStart + 1, pointStart + 33);
|
|
360
|
+
const y = publicDer.slice(pointStart + 33, pointStart + 65);
|
|
361
|
+
const header = {
|
|
362
|
+
alg: "ES256",
|
|
363
|
+
typ: "dpop+jwt",
|
|
364
|
+
jwk: {
|
|
365
|
+
kty: "EC",
|
|
366
|
+
crv: "P-256",
|
|
367
|
+
x: x.toString("base64url"),
|
|
368
|
+
y: y.toString("base64url"),
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
const payload = {
|
|
372
|
+
jti: crypto.randomUUID(),
|
|
373
|
+
htm: method,
|
|
374
|
+
htu: endpoint,
|
|
375
|
+
iat: Math.floor(Date.now() / 1000),
|
|
376
|
+
};
|
|
377
|
+
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
378
|
+
const payloadB64 = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
379
|
+
const message = `${headerB64}.${payloadB64}`;
|
|
380
|
+
const asn1Signature = sign("sha256", Buffer.from(message), privateKey);
|
|
381
|
+
const rawSignature = this.derToRawSignature(asn1Signature);
|
|
382
|
+
const signatureB64 = rawSignature.toString("base64url");
|
|
383
|
+
return `${message}.${signatureB64}`;
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
throw new CredentialsProviderError(`Failed to generate Dpop proof: ${error instanceof Error ? error.message : String(error)}`, { logger: this.logger, tryNextLink: false });
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const fromLoginCredentials = (init) => async ({ callerClientConfig } = {}) => {
|
|
392
|
+
init?.logger?.debug?.("@aws-sdk/credential-providers - fromLoginCredentials");
|
|
393
|
+
const profiles = await parseKnownFiles(init || {});
|
|
394
|
+
const profileName = getProfileName({
|
|
395
|
+
profile: init?.profile ?? callerClientConfig?.profile,
|
|
396
|
+
});
|
|
397
|
+
const profile = profiles[profileName];
|
|
398
|
+
if (!profile?.login_session) {
|
|
399
|
+
throw new CredentialsProviderError(`Profile ${profileName} does not contain login_session.`, {
|
|
400
|
+
tryNextLink: true,
|
|
401
|
+
logger: init?.logger,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
const fetcher = new LoginCredentialsFetcher(profile, init, callerClientConfig);
|
|
405
|
+
const credentials = await fetcher.loadCredentials();
|
|
406
|
+
return setCredentialFeature(credentials, "CREDENTIALS_LOGIN", "AD");
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const isLoginProfile = (data) => {
|
|
410
|
+
return Boolean(data && data.login_session);
|
|
411
|
+
};
|
|
412
|
+
const resolveLoginCredentials = async (profileName, options) => {
|
|
413
|
+
const credentials = await fromLoginCredentials({
|
|
414
|
+
...options,
|
|
415
|
+
profile: profileName,
|
|
416
|
+
})();
|
|
417
|
+
return setCredentialFeature(credentials, "CREDENTIALS_PROFILE_LOGIN", "AC");
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const isProcessProfile = (arg) => Boolean(arg) && typeof arg === "object" && typeof arg.credential_process === "string";
|
|
421
|
+
const resolveProcessCredentials = async (options, profile) => import('./index-CYoFYXZv.mjs').then(({ fromProcess }) => fromProcess({
|
|
422
|
+
...options,
|
|
423
|
+
profile,
|
|
424
|
+
})().then((creds) => setCredentialFeature(creds, "CREDENTIALS_PROFILE_PROCESS", "v")));
|
|
425
|
+
|
|
426
|
+
const resolveSsoCredentials = async (profile, profileData, options = {}) => {
|
|
427
|
+
const { fromSSO } = await import('./index-C4Ac6feq.mjs');
|
|
428
|
+
return fromSSO({
|
|
429
|
+
profile,
|
|
430
|
+
logger: options.logger,
|
|
431
|
+
parentClientConfig: options.parentClientConfig,
|
|
432
|
+
clientConfig: options.clientConfig,
|
|
433
|
+
})().then((creds) => {
|
|
434
|
+
if (profileData.sso_session) {
|
|
435
|
+
return setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO", "r");
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
return setCredentialFeature(creds, "CREDENTIALS_PROFILE_SSO_LEGACY", "t");
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
};
|
|
442
|
+
const isSsoProfile = (arg) => arg &&
|
|
443
|
+
(typeof arg.sso_start_url === "string" ||
|
|
444
|
+
typeof arg.sso_account_id === "string" ||
|
|
445
|
+
typeof arg.sso_session === "string" ||
|
|
446
|
+
typeof arg.sso_region === "string" ||
|
|
447
|
+
typeof arg.sso_role_name === "string");
|
|
448
|
+
|
|
449
|
+
const isStaticCredsProfile = (arg) => Boolean(arg) &&
|
|
450
|
+
typeof arg === "object" &&
|
|
451
|
+
typeof arg.aws_access_key_id === "string" &&
|
|
452
|
+
typeof arg.aws_secret_access_key === "string" &&
|
|
453
|
+
["undefined", "string"].indexOf(typeof arg.aws_session_token) > -1 &&
|
|
454
|
+
["undefined", "string"].indexOf(typeof arg.aws_account_id) > -1;
|
|
455
|
+
const resolveStaticCredentials = async (profile, options) => {
|
|
456
|
+
options?.logger?.debug("@aws-sdk/credential-provider-ini - resolveStaticCredentials");
|
|
457
|
+
const credentials = {
|
|
458
|
+
accessKeyId: profile.aws_access_key_id,
|
|
459
|
+
secretAccessKey: profile.aws_secret_access_key,
|
|
460
|
+
sessionToken: profile.aws_session_token,
|
|
461
|
+
...(profile.aws_credential_scope && { credentialScope: profile.aws_credential_scope }),
|
|
462
|
+
...(profile.aws_account_id && { accountId: profile.aws_account_id }),
|
|
463
|
+
};
|
|
464
|
+
return setCredentialFeature(credentials, "CREDENTIALS_PROFILE", "n");
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const isWebIdentityProfile = (arg) => Boolean(arg) &&
|
|
468
|
+
typeof arg === "object" &&
|
|
469
|
+
typeof arg.web_identity_token_file === "string" &&
|
|
470
|
+
typeof arg.role_arn === "string" &&
|
|
471
|
+
["undefined", "string"].indexOf(typeof arg.role_session_name) > -1;
|
|
472
|
+
const resolveWebIdentityCredentials = async (profile, options) => import('./index-DLQEHTw4.mjs').then(({ fromTokenFile }) => fromTokenFile({
|
|
473
|
+
webIdentityTokenFile: profile.web_identity_token_file,
|
|
474
|
+
roleArn: profile.role_arn,
|
|
475
|
+
roleSessionName: profile.role_session_name,
|
|
476
|
+
roleAssumerWithWebIdentity: options.roleAssumerWithWebIdentity,
|
|
477
|
+
logger: options.logger,
|
|
478
|
+
parentClientConfig: options.parentClientConfig,
|
|
479
|
+
})().then((creds) => setCredentialFeature(creds, "CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN", "q")));
|
|
480
|
+
|
|
481
|
+
const resolveProfileData = async (profileName, profiles, options, visitedProfiles = {}, isAssumeRoleRecursiveCall = false) => {
|
|
482
|
+
const data = profiles[profileName];
|
|
483
|
+
if (Object.keys(visitedProfiles).length > 0 && isStaticCredsProfile(data)) {
|
|
484
|
+
return resolveStaticCredentials(data, options);
|
|
485
|
+
}
|
|
486
|
+
if (isAssumeRoleRecursiveCall || isAssumeRoleProfile(data, { profile: profileName, logger: options.logger })) {
|
|
487
|
+
return resolveAssumeRoleCredentials(profileName, profiles, options, visitedProfiles, resolveProfileData);
|
|
488
|
+
}
|
|
489
|
+
if (isStaticCredsProfile(data)) {
|
|
490
|
+
return resolveStaticCredentials(data, options);
|
|
491
|
+
}
|
|
492
|
+
if (isWebIdentityProfile(data)) {
|
|
493
|
+
return resolveWebIdentityCredentials(data, options);
|
|
494
|
+
}
|
|
495
|
+
if (isProcessProfile(data)) {
|
|
496
|
+
return resolveProcessCredentials(options, profileName);
|
|
497
|
+
}
|
|
498
|
+
if (isSsoProfile(data)) {
|
|
499
|
+
return await resolveSsoCredentials(profileName, data, options);
|
|
500
|
+
}
|
|
501
|
+
if (isLoginProfile(data)) {
|
|
502
|
+
return resolveLoginCredentials(profileName, options);
|
|
503
|
+
}
|
|
504
|
+
throw new CredentialsProviderError(`Could not resolve credentials using profile: [${profileName}] in configuration/credentials file(s).`, { logger: options.logger });
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
const fromIni = (_init = {}) => async ({ callerClientConfig } = {}) => {
|
|
508
|
+
const init = {
|
|
509
|
+
..._init,
|
|
510
|
+
parentClientConfig: {
|
|
511
|
+
...callerClientConfig,
|
|
512
|
+
..._init.parentClientConfig,
|
|
513
|
+
},
|
|
514
|
+
};
|
|
515
|
+
init.logger?.debug("@aws-sdk/credential-provider-ini - fromIni");
|
|
516
|
+
const profiles = await parseKnownFiles(init);
|
|
517
|
+
return resolveProfileData(getProfileName({
|
|
518
|
+
profile: _init.profile ?? callerClientConfig?.profile,
|
|
519
|
+
}), profiles, init);
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
export { fromIni };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compose a child-process env overlay from dotenv and the merged CLI options bag.
|
|
3
|
+
* Returns a shallow object including getDotenvCliOptions when serializable.
|
|
4
|
+
*
|
|
5
|
+
* @param merged - Resolved CLI options bag (or a JSON-serializable subset).
|
|
6
|
+
* @param dotenv - Composed dotenv variables for the current invocation.
|
|
7
|
+
* @returns A string-only env overlay suitable for child process spawning.
|
|
8
|
+
*/
|
|
9
|
+
function composeNestedEnv(merged, dotenv) {
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const [k, v] of Object.entries(dotenv)) {
|
|
12
|
+
if (typeof v === 'string')
|
|
13
|
+
out[k] = v;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const { logger: _omit, ...bag } = merged;
|
|
17
|
+
const txt = JSON.stringify(bag);
|
|
18
|
+
if (typeof txt === 'string')
|
|
19
|
+
out.getDotenvCliOptions = txt;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
/* best-effort only */
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Strip one layer of symmetric outer quotes (single or double) from a string.
|
|
28
|
+
*
|
|
29
|
+
* @param s - Input string.
|
|
30
|
+
* @returns `s` without one symmetric outer quote pair (when present).
|
|
31
|
+
*/
|
|
32
|
+
const stripOne = (s) => {
|
|
33
|
+
if (s.length < 2)
|
|
34
|
+
return s;
|
|
35
|
+
const a = s.charAt(0);
|
|
36
|
+
const b = s.charAt(s.length - 1);
|
|
37
|
+
const symmetric = (a === '"' && b === '"') || (a === "'" && b === "'");
|
|
38
|
+
return symmetric ? s.slice(1, -1) : s;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Preserve argv array for Node -e/--eval payloads under shell-off and
|
|
42
|
+
* peel one symmetric outer quote layer from the code argument.
|
|
43
|
+
*
|
|
44
|
+
* @param args - Argument vector intended for direct execution (shell-off).
|
|
45
|
+
* @returns Either the original `args` or a modified copy with a normalized eval payload.
|
|
46
|
+
*/
|
|
47
|
+
function maybePreserveNodeEvalArgv(args) {
|
|
48
|
+
if (args.length >= 3) {
|
|
49
|
+
const first = (args[0] ?? '').toLowerCase();
|
|
50
|
+
const hasEval = args[1] === '-e' || args[1] === '--eval';
|
|
51
|
+
if (first === 'node' && hasEval) {
|
|
52
|
+
const copy = args.slice();
|
|
53
|
+
copy[2] = stripOne(copy[2] ?? '');
|
|
54
|
+
return copy;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return args;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { composeNestedEnv as c, maybePreserveNodeEvalArgv as m, stripOne as s };
|