@microsoft/yarn-plugin-ado-auth 0.1.1
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/LICENSE.txt +21 -0
- package/README.md +257 -0
- package/dist/yarn-plugin-ado-auth.cjs +648 -0
- package/dist/yarn-plugin-ado-auth.cjs.map +7 -0
- package/lib/configuration.d.ts +8 -0
- package/lib/configuration.d.ts.map +1 -0
- package/lib/configuration.js +23 -0
- package/lib/configuration.js.map +1 -0
- package/lib/getToken.d.ts +12 -0
- package/lib/getToken.d.ts.map +1 -0
- package/lib/getToken.js +13 -0
- package/lib/getToken.js.map +1 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +6 -0
- package/lib/index.js.map +1 -0
- package/lib/plugin.d.ts +7 -0
- package/lib/plugin.d.ts.map +1 -0
- package/lib/plugin.js +33 -0
- package/lib/plugin.js.map +1 -0
- package/lib/tokenCache.d.ts +45 -0
- package/lib/tokenCache.d.ts.map +1 -0
- package/lib/tokenCache.js +126 -0
- package/lib/tokenCache.js.map +1 -0
- package/lib/utils.d.ts +9 -0
- package/lib/utils.d.ts.map +1 -0
- package/lib/utils.js +27 -0
- package/lib/utils.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
//prettier-ignore
|
|
3
|
+
module.exports = {
|
|
4
|
+
name: "yarn-plugin-ado-auth",
|
|
5
|
+
factory: function (require) {
|
|
6
|
+
"use strict";
|
|
7
|
+
var plugin = (() => {
|
|
8
|
+
var __create = Object.create;
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
15
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
16
|
+
}) : x)(function(x) {
|
|
17
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
18
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
19
|
+
});
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
23
|
+
};
|
|
24
|
+
var __copyProps = (to, from, except, desc) => {
|
|
25
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
26
|
+
for (let key of __getOwnPropNames(from))
|
|
27
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
28
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
29
|
+
}
|
|
30
|
+
return to;
|
|
31
|
+
};
|
|
32
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
33
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
34
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
35
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
36
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
37
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
38
|
+
mod
|
|
39
|
+
));
|
|
40
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
41
|
+
|
|
42
|
+
// src/plugin.ts
|
|
43
|
+
var plugin_exports = {};
|
|
44
|
+
__export(plugin_exports, {
|
|
45
|
+
default: () => plugin_default
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// src/tokenCache.ts
|
|
49
|
+
var import_core2 = __require("@yarnpkg/core");
|
|
50
|
+
|
|
51
|
+
// ../ado-npm-auth/lib/utils/get-organization-from-feed-url.js
|
|
52
|
+
var extractAdoDetails = (url) => {
|
|
53
|
+
try {
|
|
54
|
+
if (!url.startsWith("https://")) {
|
|
55
|
+
url = "https://" + url;
|
|
56
|
+
}
|
|
57
|
+
const parsedUrl = new URL(url);
|
|
58
|
+
const hostname2 = parsedUrl.hostname;
|
|
59
|
+
const pathname = parsedUrl.pathname;
|
|
60
|
+
if (hostname2.endsWith("dev.azure.com")) {
|
|
61
|
+
const pathSegments = pathname.split("/").filter(Boolean);
|
|
62
|
+
if (pathSegments.length >= 2) {
|
|
63
|
+
return {
|
|
64
|
+
organization: pathSegments[0],
|
|
65
|
+
project: pathSegments[1]
|
|
66
|
+
};
|
|
67
|
+
} else {
|
|
68
|
+
throw new Error("Not enough segments in path for a valid organization and project extraction.");
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (hostname2.endsWith("visualstudio.com")) {
|
|
72
|
+
const subdomain = hostname2.split(".")[0];
|
|
73
|
+
const pathSegments = pathname.split("/").filter(Boolean);
|
|
74
|
+
if (subdomain && pathSegments.length >= 1) {
|
|
75
|
+
return {
|
|
76
|
+
organization: subdomain,
|
|
77
|
+
project: pathSegments[0]
|
|
78
|
+
};
|
|
79
|
+
} else {
|
|
80
|
+
throw new Error("Not enough segments in path or missing subdomain for a valid organization and project extraction.");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
throw new Error("URL format not recognized or does not contain enough information.");
|
|
84
|
+
} catch {
|
|
85
|
+
throw new Error("Invalid URL or unsupported format");
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
var getOrganizationFromFeedUrl = (feedUrl, defaultOrg = "") => {
|
|
89
|
+
try {
|
|
90
|
+
const { organization } = extractAdoDetails(feedUrl);
|
|
91
|
+
return organization;
|
|
92
|
+
} catch {
|
|
93
|
+
return defaultOrg;
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// ../ado-npm-auth/lib/utils/encoding.js
|
|
98
|
+
function toBase64(input) {
|
|
99
|
+
return Buffer.from(input || "").toString("base64");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ../ado-npm-auth/lib/utils/request.js
|
|
103
|
+
var import_https = __toESM(__require("https"), 1);
|
|
104
|
+
var import_fs = __toESM(__require("fs"), 1);
|
|
105
|
+
var import_path = __toESM(__require("path"), 1);
|
|
106
|
+
async function downloadFile(url, downloadPath) {
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
import_https.default.get(url, (response) => {
|
|
109
|
+
if (response.statusCode === 301 || response.statusCode === 302) {
|
|
110
|
+
const redirectUrl = response.headers.location;
|
|
111
|
+
if (redirectUrl) {
|
|
112
|
+
downloadFile(redirectUrl, downloadPath).then(resolve).catch(reject);
|
|
113
|
+
return;
|
|
114
|
+
} else {
|
|
115
|
+
reject(new Error("Redirect without location header"));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (response.statusCode !== 200) {
|
|
120
|
+
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
let downloadStream;
|
|
124
|
+
try {
|
|
125
|
+
const downloadDir = import_path.default.dirname(downloadPath);
|
|
126
|
+
if (!import_fs.default.existsSync(downloadDir)) {
|
|
127
|
+
import_fs.default.mkdirSync(downloadDir, { recursive: true });
|
|
128
|
+
}
|
|
129
|
+
downloadStream = import_fs.default.createWriteStream(downloadPath);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
reject(error);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
downloadStream.on("error", (error) => {
|
|
135
|
+
reject(error);
|
|
136
|
+
});
|
|
137
|
+
response.pipe(downloadStream);
|
|
138
|
+
downloadStream.on("finish", () => {
|
|
139
|
+
resolve();
|
|
140
|
+
});
|
|
141
|
+
}).on("error", (error) => {
|
|
142
|
+
reject(error);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ../ado-npm-auth/lib/npmrc/generate-npmrc-pat.js
|
|
148
|
+
var import_os5 = __require("os");
|
|
149
|
+
|
|
150
|
+
// ../ado-npm-auth/lib/azureauth/ado.js
|
|
151
|
+
var import_os3 = __require("os");
|
|
152
|
+
|
|
153
|
+
// ../ado-npm-auth/lib/utils/exec.js
|
|
154
|
+
var import_node_child_process = __require("child_process");
|
|
155
|
+
var import_node_util = __require("util");
|
|
156
|
+
var exec = (0, import_node_util.promisify)(import_node_child_process.exec);
|
|
157
|
+
function execProcess(tool, args, options) {
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
159
|
+
var _a, _b, _c, _d;
|
|
160
|
+
const cwd = (options === null || options === void 0 ? void 0 : options.cwd) || process.cwd();
|
|
161
|
+
console.log(`🚀 Launching [${tool} ${args.join(" ")}] in ${cwd}`);
|
|
162
|
+
const result = (0, import_node_child_process.spawn)(tool, args, {
|
|
163
|
+
cwd,
|
|
164
|
+
env: (options === null || options === void 0 ? void 0 : options.env) || process.env,
|
|
165
|
+
stdio: (options === null || options === void 0 ? void 0 : options.stdio) || "inherit",
|
|
166
|
+
shell: (options === null || options === void 0 ? void 0 : options.shell) || false
|
|
167
|
+
});
|
|
168
|
+
if ((options === null || options === void 0 ? void 0 : options.stdio) === "pipe") {
|
|
169
|
+
(_a = result.stdout) === null || _a === void 0 ? void 0 : _a.setEncoding("utf8");
|
|
170
|
+
(_b = result.stdout) === null || _b === void 0 ? void 0 : _b.on("data", function(data) {
|
|
171
|
+
var _a2;
|
|
172
|
+
const strData = data.toString("utf8");
|
|
173
|
+
(_a2 = options === null || options === void 0 ? void 0 : options.processStdOut) === null || _a2 === void 0 ? void 0 : _a2.call(options, strData);
|
|
174
|
+
});
|
|
175
|
+
(_c = result.stderr) === null || _c === void 0 ? void 0 : _c.setEncoding("utf8");
|
|
176
|
+
(_d = result.stderr) === null || _d === void 0 ? void 0 : _d.on("data", function(data) {
|
|
177
|
+
var _a2;
|
|
178
|
+
const strData = data.toString("utf8");
|
|
179
|
+
(_a2 = options === null || options === void 0 ? void 0 : options.processStdErr) === null || _a2 === void 0 ? void 0 : _a2.call(options, strData);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
result.on("exit", (code) => {
|
|
183
|
+
if (code == 0) {
|
|
184
|
+
resolve();
|
|
185
|
+
} else {
|
|
186
|
+
reject(new Error(`Process ${tool} exited with code ${code}`));
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ../ado-npm-auth/lib/azureauth/is-supported-platform-and-architecture.js
|
|
193
|
+
var import_os2 = __require("os");
|
|
194
|
+
|
|
195
|
+
// ../ado-npm-auth/lib/utils/is-wsl.js
|
|
196
|
+
var import_os = __require("os");
|
|
197
|
+
var isWsl = () => {
|
|
198
|
+
return (0, import_os.platform)() === "linux" && (0, import_os.release)().toLowerCase().includes("wsl");
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// ../ado-npm-auth/lib/azureauth/is-supported-platform-and-architecture.js
|
|
202
|
+
var isSupportedPlatformAndArchitecture = () => {
|
|
203
|
+
const supportedPlatformsAndArchitectures = {
|
|
204
|
+
win32: ["x64"],
|
|
205
|
+
darwin: ["x64", "arm64"]
|
|
206
|
+
};
|
|
207
|
+
return isWsl() || supportedPlatformsAndArchitectures[(0, import_os2.platform)()] && supportedPlatformsAndArchitectures[(0, import_os2.platform)()].includes((0, import_os2.arch)());
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// ../ado-npm-auth/lib/azureauth/azureauth-command.js
|
|
211
|
+
var memo = void 0;
|
|
212
|
+
var npxAzureAuthCommand = [
|
|
213
|
+
"npm",
|
|
214
|
+
"exec",
|
|
215
|
+
"--silent",
|
|
216
|
+
"--yes",
|
|
217
|
+
"azureauth",
|
|
218
|
+
"--"
|
|
219
|
+
];
|
|
220
|
+
var npxEnv = {
|
|
221
|
+
...process.env,
|
|
222
|
+
// Use the version from the public registry to avoid a cycle
|
|
223
|
+
npm_config_registry: "https://registry.npmjs.org"
|
|
224
|
+
};
|
|
225
|
+
var azureAuthCommand = () => {
|
|
226
|
+
if (!memo) {
|
|
227
|
+
memo = isWsl() ? ["azureauth.exe"] : npxAzureAuthCommand;
|
|
228
|
+
}
|
|
229
|
+
return { command: memo, env: npxEnv };
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// ../ado-npm-auth/lib/azureauth/ado.js
|
|
233
|
+
var import_child_process = __require("child_process");
|
|
234
|
+
|
|
235
|
+
// ../ado-npm-auth/lib/azureauth/is-azureauth-installed.js
|
|
236
|
+
var memo2 = void 0;
|
|
237
|
+
var isAzureAuthInstalled = async () => {
|
|
238
|
+
if (memo2 === void 0) {
|
|
239
|
+
const { command: authCommand, env } = azureAuthCommand();
|
|
240
|
+
const command = `${authCommand.join(" ")} --version`;
|
|
241
|
+
try {
|
|
242
|
+
const result = await exec(command, { env });
|
|
243
|
+
const [, minor] = result.stdout.split(".");
|
|
244
|
+
memo2 = parseInt(minor) >= 8;
|
|
245
|
+
} catch {
|
|
246
|
+
memo2 = false;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return memo2;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// ../ado-npm-auth/lib/azureauth/ado.js
|
|
253
|
+
var adoPat = async (options, azureAuthLocation) => {
|
|
254
|
+
if (!isSupportedPlatformAndArchitecture()) {
|
|
255
|
+
throw new Error(`AzureAuth is not supported for platform ${(0, import_os3.platform)()} and architecture ${(0, import_os3.arch)()}`);
|
|
256
|
+
}
|
|
257
|
+
const { command: authCommand, env } = azureAuthLocation ? {
|
|
258
|
+
command: [azureAuthLocation],
|
|
259
|
+
env: process.env
|
|
260
|
+
} : azureAuthCommand();
|
|
261
|
+
const command = [
|
|
262
|
+
...authCommand,
|
|
263
|
+
`ado`,
|
|
264
|
+
`pat`,
|
|
265
|
+
`--prompt-hint ${isWsl() ? options.promptHint : `"${options.promptHint}"`}`,
|
|
266
|
+
// We only use spawn for WSL. spawn does not does not require prompt hint to be wrapped in quotes. exec does.
|
|
267
|
+
`--organization ${options.organization}`,
|
|
268
|
+
`--display-name ${options.displayName}`,
|
|
269
|
+
...options.scope.map((scope) => `--scope ${scope}`)
|
|
270
|
+
];
|
|
271
|
+
if (options.output) {
|
|
272
|
+
command.push(`--output ${options.output}`);
|
|
273
|
+
}
|
|
274
|
+
if (options.mode) {
|
|
275
|
+
command.push(`--mode ${options.mode}`);
|
|
276
|
+
}
|
|
277
|
+
if (options.domain) {
|
|
278
|
+
command.push(`--domain ${options.domain}`);
|
|
279
|
+
}
|
|
280
|
+
if (options.timeout) {
|
|
281
|
+
command.push(`--timeout ${options.timeout}`);
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
let result;
|
|
285
|
+
if (isWsl()) {
|
|
286
|
+
try {
|
|
287
|
+
result = (0, import_child_process.spawnSync)(command[0], command.slice(1), { encoding: "utf-8" });
|
|
288
|
+
if (result.status !== 0 || result.stderr && !result.stdout) {
|
|
289
|
+
throw new Error(`Azure Auth failed with exit code ${result.status}: ${result.stderr}`);
|
|
290
|
+
}
|
|
291
|
+
} catch (error) {
|
|
292
|
+
throw new Error(`Failed to get Ado Pat from system AzureAuth: ${error.message}`);
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
try {
|
|
296
|
+
result = await exec(command.join(" "), { env });
|
|
297
|
+
if (result.stderr && !result.stdout) {
|
|
298
|
+
throw new Error(result.stderr);
|
|
299
|
+
}
|
|
300
|
+
} catch (error) {
|
|
301
|
+
throw new Error(`Failed to get Ado Pat from npx AzureAuth: ${error.message}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (options.output === "json") {
|
|
305
|
+
try {
|
|
306
|
+
return JSON.parse(result.stdout);
|
|
307
|
+
} catch {
|
|
308
|
+
throw new Error(`Failed to parse JSON output: ${result.stdout}`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return result.stdout;
|
|
312
|
+
} catch (error) {
|
|
313
|
+
if (!await isAzureAuthInstalled()) {
|
|
314
|
+
throw new Error(`AzureAuth is not installed: ${error}`);
|
|
315
|
+
}
|
|
316
|
+
throw new Error(error.message);
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// ../ado-npm-auth/lib/npmrc/nugetCredentialProvider.js
|
|
321
|
+
var import_os4 = __toESM(__require("os"), 1);
|
|
322
|
+
var import_fs2 = __toESM(__require("fs"), 1);
|
|
323
|
+
var import_path2 = __toESM(__require("path"), 1);
|
|
324
|
+
var import_url = __require("url");
|
|
325
|
+
var import_meta = {};
|
|
326
|
+
var CredentialProviderVersion = "1.4.1";
|
|
327
|
+
var OutputDir = import_path2.default.join(import_path2.default.dirname((0, import_url.fileURLToPath)(import_meta.url)), "..", ".bin", "CredentialProvider.Microsoft", "v" + CredentialProviderVersion);
|
|
328
|
+
async function credentialProviderPat(registry) {
|
|
329
|
+
const nugetFeedUrl = toNugetUrl(registry);
|
|
330
|
+
const toolPath = await getCredentialProvider();
|
|
331
|
+
return await invokeCredentialProvider(toolPath, nugetFeedUrl);
|
|
332
|
+
}
|
|
333
|
+
function toNugetUrl(registry) {
|
|
334
|
+
if (!registry.endsWith("/npm/registry/")) {
|
|
335
|
+
throw new Error(`Registry URL ${registry} is not a valid Azure Artifacts npm registry URL. Expected it to end with '/npm/registry/'`);
|
|
336
|
+
}
|
|
337
|
+
return "https://" + registry.replace("/npm/registry/", "/nuget/v3/index.json");
|
|
338
|
+
}
|
|
339
|
+
async function invokeCredentialProvider(toolPath, nugetFeedUrl) {
|
|
340
|
+
let response = "";
|
|
341
|
+
await execProcess(toolPath, ["-U", nugetFeedUrl, "-I", "-F", "Json"], {
|
|
342
|
+
stdio: "pipe",
|
|
343
|
+
processStdOut: (data) => {
|
|
344
|
+
response += data;
|
|
345
|
+
},
|
|
346
|
+
processStdErr: (data) => {
|
|
347
|
+
console.error(data);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
try {
|
|
351
|
+
const value = JSON.parse(response);
|
|
352
|
+
return value;
|
|
353
|
+
} catch {
|
|
354
|
+
throw new Error(`Failed to parse CredentialProvider output: ${response}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function tryFileExists(executable) {
|
|
358
|
+
if (import_fs2.default.existsSync(executable)) {
|
|
359
|
+
return executable;
|
|
360
|
+
} else if (import_fs2.default.existsSync(executable + ".exe")) {
|
|
361
|
+
return executable + ".exe";
|
|
362
|
+
}
|
|
363
|
+
return void 0;
|
|
364
|
+
}
|
|
365
|
+
async function getCredentialProvider() {
|
|
366
|
+
let toolPath = tryFileExists(import_path2.default.join(import_os4.default.homedir(), ".nuget", "plugins", "netcore", "CredentialProvider.Microsoft", "CredentialProvider.Microsoft"));
|
|
367
|
+
if (toolPath) {
|
|
368
|
+
return toolPath;
|
|
369
|
+
}
|
|
370
|
+
const downloadedFilePath = import_path2.default.join(OutputDir, "plugins", "netcore", "CredentialProvider.Microsoft", "CredentialProvider.Microsoft");
|
|
371
|
+
toolPath = tryFileExists(downloadedFilePath);
|
|
372
|
+
if (toolPath) {
|
|
373
|
+
return toolPath;
|
|
374
|
+
}
|
|
375
|
+
await downloadCredentialProvider();
|
|
376
|
+
toolPath = tryFileExists(downloadedFilePath);
|
|
377
|
+
if (toolPath) {
|
|
378
|
+
import_fs2.default.chmodSync(toolPath, 493);
|
|
379
|
+
} else {
|
|
380
|
+
throw new Error(`CredentialProvider was not found at expected path after download: ${toolPath}`);
|
|
381
|
+
}
|
|
382
|
+
return toolPath;
|
|
383
|
+
}
|
|
384
|
+
async function downloadCredentialProvider() {
|
|
385
|
+
const downloadUrl = `https://github.com/microsoft/artifacts-credprovider/releases/download/v${CredentialProviderVersion}/Microsoft.Net8.${import_os4.default.platform()}-${import_os4.default.arch()}.NuGet.CredentialProvider.tar.gz`;
|
|
386
|
+
const downloadPath = import_path2.default.join(OutputDir, "CredentialProvider.Microsoft.tar.gz");
|
|
387
|
+
console.log(`🌐 Downloading ${downloadUrl}`);
|
|
388
|
+
await downloadFile(downloadUrl, downloadPath);
|
|
389
|
+
await execProcess("tar", ["-xzf", downloadPath, "-C", OutputDir], {
|
|
390
|
+
stdio: "inherit"
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// ../ado-npm-auth/lib/npmrc/generate-npmrc-pat.js
|
|
395
|
+
var generateNpmrcPat = async (organization, feed, encode = false, azureAuthLocation) => {
|
|
396
|
+
const name = `${(0, import_os5.hostname)()}-${organization}`;
|
|
397
|
+
const rawToken = await getRawToken(name, organization, feed, azureAuthLocation);
|
|
398
|
+
if (encode) {
|
|
399
|
+
return toBase64(rawToken);
|
|
400
|
+
}
|
|
401
|
+
return rawToken;
|
|
402
|
+
};
|
|
403
|
+
async function getRawToken(name, organization, feed, azureAuthLocation) {
|
|
404
|
+
const patScope = "vso.packaging_write";
|
|
405
|
+
switch ((0, import_os5.platform)()) {
|
|
406
|
+
case "win32":
|
|
407
|
+
case "darwin": {
|
|
408
|
+
const pat = await adoPat({
|
|
409
|
+
promptHint: `Authenticate to ${organization} to generate a temporary token for npm`,
|
|
410
|
+
organization,
|
|
411
|
+
displayName: name,
|
|
412
|
+
scope: [patScope],
|
|
413
|
+
timeout: "30",
|
|
414
|
+
output: "json"
|
|
415
|
+
}, azureAuthLocation);
|
|
416
|
+
return pat.token;
|
|
417
|
+
}
|
|
418
|
+
case "linux": {
|
|
419
|
+
const cpPat = await credentialProviderPat(feed);
|
|
420
|
+
return cpPat.Password;
|
|
421
|
+
}
|
|
422
|
+
default:
|
|
423
|
+
throw new Error(`Platform ${(0, import_os5.platform)()} is not supported for ADO authentication`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// src/configuration.ts
|
|
428
|
+
var import_core = __require("@yarnpkg/core");
|
|
429
|
+
|
|
430
|
+
// src/utils.ts
|
|
431
|
+
function getConfigString(config, key, required = false) {
|
|
432
|
+
const value = config?.get(key);
|
|
433
|
+
if (typeof value === "string") {
|
|
434
|
+
return value;
|
|
435
|
+
} else if (required) {
|
|
436
|
+
throw new Error(`Expected configuration key "${key}" to be a string`);
|
|
437
|
+
}
|
|
438
|
+
return void 0;
|
|
439
|
+
}
|
|
440
|
+
function getConfigMap(config, key) {
|
|
441
|
+
const value = config?.get(key);
|
|
442
|
+
if (value && value.get !== void 0) {
|
|
443
|
+
return value;
|
|
444
|
+
}
|
|
445
|
+
return void 0;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// src/configuration.ts
|
|
449
|
+
function getConfiguration() {
|
|
450
|
+
return {
|
|
451
|
+
adoNpmAuthToolPath: {
|
|
452
|
+
description: `The path to the ADO authentication tool`,
|
|
453
|
+
type: import_core.SettingsType.STRING,
|
|
454
|
+
default: null
|
|
455
|
+
},
|
|
456
|
+
adoNpmAuthFeedPrefix: {
|
|
457
|
+
description: `The prefix to use for ADO NPM feed URLs`,
|
|
458
|
+
type: import_core.SettingsType.STRING,
|
|
459
|
+
default: `https://pkgs.dev.azure.com/`
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function loadConfiguration(configuration) {
|
|
464
|
+
return {
|
|
465
|
+
adoNpmAuthToolPath: getConfigString(configuration, "adoNpmAuthToolPath"),
|
|
466
|
+
adoNpmAuthFeedPrefix: getConfigString(
|
|
467
|
+
configuration,
|
|
468
|
+
"adoNpmAuthFeedPrefix",
|
|
469
|
+
true
|
|
470
|
+
)
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/tokenCache.ts
|
|
475
|
+
var import_node_child_process2 = __require("child_process");
|
|
476
|
+
var import_node_os = __toESM(__require("os"), 1);
|
|
477
|
+
var TokenCache = class {
|
|
478
|
+
constructor(configuration, loadConfig = loadConfiguration) {
|
|
479
|
+
this.cache = {};
|
|
480
|
+
this.configuration = configuration;
|
|
481
|
+
const settings = loadConfig(configuration);
|
|
482
|
+
this.prefix = settings.adoNpmAuthFeedPrefix ?? "";
|
|
483
|
+
this.azureAuthPath = settings.adoNpmAuthToolPath || findAzureAuthPath();
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Will return the token for the given registry, either from cache or by fetching a new one. If it is in
|
|
487
|
+
* the cache already, it will return it directly. Otherwise it will return a promise that resolves to the token
|
|
488
|
+
* @param registry the registry/feed that we need to authenticate against
|
|
489
|
+
*/
|
|
490
|
+
getToken(registry, ident) {
|
|
491
|
+
if (!this.prefix || registry.startsWith(this.prefix)) {
|
|
492
|
+
return this.cache[registry] ??= this.fetchToken(registry, ident);
|
|
493
|
+
}
|
|
494
|
+
return void 0;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Do the work to fetch a token for the given registry. This will attempt to get it from yarnrc/env first,
|
|
498
|
+
* and if not found, will use the ADO CLI to get a new token.
|
|
499
|
+
*
|
|
500
|
+
* @param registry registry to authenticate to
|
|
501
|
+
* @param ident optional ident, used for configuration lookups (yarn pass through)
|
|
502
|
+
* @returns a promise that resolves to a string
|
|
503
|
+
*/
|
|
504
|
+
async fetchToken(registry, ident) {
|
|
505
|
+
const configuration = this.configuration;
|
|
506
|
+
await import_core2.StreamReport.start(
|
|
507
|
+
{ configuration, stdout: process.stdout },
|
|
508
|
+
async (report) => {
|
|
509
|
+
const prettyRegistry = import_core2.formatUtils.pretty(
|
|
510
|
+
configuration,
|
|
511
|
+
registry,
|
|
512
|
+
import_core2.formatUtils.Type.URL
|
|
513
|
+
);
|
|
514
|
+
const authConfig = this.getAuthConfiguration(registry, ident);
|
|
515
|
+
const tokenFromYarnrc = getConfigString(authConfig, "npmAuthToken");
|
|
516
|
+
if (tokenFromYarnrc) {
|
|
517
|
+
this.cache[registry] = tokenFromYarnrc;
|
|
518
|
+
report.reportInfo(
|
|
519
|
+
null,
|
|
520
|
+
`Authenticated to: ${prettyRegistry} (via configuration)`
|
|
521
|
+
);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
const organization = getOrganizationFromFeedUrl(registry);
|
|
525
|
+
if (!organization) {
|
|
526
|
+
throw new Error(
|
|
527
|
+
`Could not determine organization from registry URL: ${registry}`
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
const pat2 = await generateNpmrcPat(
|
|
531
|
+
organization,
|
|
532
|
+
registry,
|
|
533
|
+
false,
|
|
534
|
+
this.azureAuthPath
|
|
535
|
+
);
|
|
536
|
+
this.cache[registry] = pat2;
|
|
537
|
+
report.reportInfo(
|
|
538
|
+
null,
|
|
539
|
+
`Authenticated to: ${prettyRegistry} (via ADO CLI)`
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
);
|
|
543
|
+
const pat = this.cache[registry];
|
|
544
|
+
if (pat == null) {
|
|
545
|
+
throw new Error(`Failed to authenticate to: ${registry}`);
|
|
546
|
+
}
|
|
547
|
+
return pat;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Get the authentication configuration for the given registry and ident. This code was
|
|
551
|
+
* taken from Yarn's npm plugin to match their logic. Importing that package directly results in
|
|
552
|
+
* a massive bundle, so extracted just this logic.
|
|
553
|
+
*/
|
|
554
|
+
getAuthConfiguration(registry, ident) {
|
|
555
|
+
const scopeConfiguration = ident && this.getScopeConfiguration(ident.scope);
|
|
556
|
+
if (scopeConfiguration?.get(`npmAuthToken`)) {
|
|
557
|
+
return scopeConfiguration;
|
|
558
|
+
}
|
|
559
|
+
const registryConfiguration = this.getRegistryConfiguration(registry);
|
|
560
|
+
return registryConfiguration ?? this.configuration;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Return the auth configuration for the given scope if one has been set
|
|
564
|
+
* @param scope package scope to use for lookups
|
|
565
|
+
*/
|
|
566
|
+
getScopeConfiguration(scope) {
|
|
567
|
+
if (scope != null) {
|
|
568
|
+
const scopeConfigurations = getConfigMap(this.configuration, `npmScopes`);
|
|
569
|
+
const scopeConfiguration = getConfigMap(scopeConfigurations, scope);
|
|
570
|
+
if (scopeConfiguration) {
|
|
571
|
+
return scopeConfiguration;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return null;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Return the auth configuration for the given registry if one has been set
|
|
578
|
+
* @param registry registry to get configuration for
|
|
579
|
+
*/
|
|
580
|
+
getRegistryConfiguration(registry) {
|
|
581
|
+
const registryConfigurations = getConfigMap(
|
|
582
|
+
this.configuration,
|
|
583
|
+
`npmRegistries`
|
|
584
|
+
);
|
|
585
|
+
const normalizedRegistry = registry.replace(/\/$/, ``);
|
|
586
|
+
const exactEntry = getConfigMap(registryConfigurations, normalizedRegistry);
|
|
587
|
+
if (typeof exactEntry !== `undefined`) {
|
|
588
|
+
return exactEntry;
|
|
589
|
+
}
|
|
590
|
+
const noProtocolEntry = getConfigMap(
|
|
591
|
+
registryConfigurations,
|
|
592
|
+
normalizedRegistry.replace(/^[a-z]+:/, ``)
|
|
593
|
+
);
|
|
594
|
+
return noProtocolEntry ?? null;
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
function findAzureAuthPath() {
|
|
598
|
+
const isWin = import_node_os.default.platform() === "win32";
|
|
599
|
+
const execName = isWin ? "azureauth.exe" : "azureauth";
|
|
600
|
+
const cmd = isWin ? "where" : "which";
|
|
601
|
+
try {
|
|
602
|
+
const result = (0, import_node_child_process2.spawnSync)(cmd, [execName], { encoding: "utf-8" });
|
|
603
|
+
if (result.status === 0 && result.stdout) {
|
|
604
|
+
const line = result.stdout.split(/\r?\n/).find(Boolean);
|
|
605
|
+
return line ? line.trim() : void 0;
|
|
606
|
+
}
|
|
607
|
+
} catch {
|
|
608
|
+
}
|
|
609
|
+
return void 0;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// src/getToken.ts
|
|
613
|
+
var getToken = /* @__PURE__ */ (() => {
|
|
614
|
+
let tokenCache = void 0;
|
|
615
|
+
return (options, registry) => {
|
|
616
|
+
tokenCache ??= new TokenCache(options.configuration);
|
|
617
|
+
return tokenCache.getToken(registry, options.ident);
|
|
618
|
+
};
|
|
619
|
+
})();
|
|
620
|
+
|
|
621
|
+
// src/plugin.ts
|
|
622
|
+
async function getNpmAuthenticationHeader(currentHeader, registry, options) {
|
|
623
|
+
const customToken = getToken(options, registry);
|
|
624
|
+
if (customToken !== void 0) {
|
|
625
|
+
const token = typeof customToken === "string" ? customToken : await customToken;
|
|
626
|
+
return `Bearer ${token}`;
|
|
627
|
+
}
|
|
628
|
+
return currentHeader;
|
|
629
|
+
}
|
|
630
|
+
var plugin = {
|
|
631
|
+
/**
|
|
632
|
+
* Add the plugin configuration options
|
|
633
|
+
*/
|
|
634
|
+
configuration: getConfiguration(),
|
|
635
|
+
/**
|
|
636
|
+
* Add a hook to authenticate on demand with npm feeds
|
|
637
|
+
*/
|
|
638
|
+
hooks: {
|
|
639
|
+
getNpmAuthenticationHeader
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
var plugin_default = plugin;
|
|
643
|
+
return __toCommonJS(plugin_exports);
|
|
644
|
+
})();
|
|
645
|
+
return plugin;
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
//# sourceMappingURL=yarn-plugin-ado-auth.cjs.map
|