artifact-engine 1.271.1 → 2.272.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/Engine/cilogger.js +1 -1
- package/Providers/typed-rest-client/handlers/basiccreds.js +1 -1
- package/Providers/typed-rest-client/handlers/ntlm.js +31 -20
- package/Providers/typed-rest-client/handlers/personalaccesstoken.js +1 -1
- package/Providers/typed-rest-client/opensource/node-http-ntlm/ntlm.js +26 -29
- package/Providers/webClientFactory.js +8 -5
- package/README.md +4 -4
- package/lib.json +2 -2
- package/package.json +12 -13
package/Engine/cilogger.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.publishEvent = void 0;
|
|
4
4
|
var tl = require('azure-pipelines-task-lib');
|
|
5
5
|
var packagejson = require('../package.json');
|
|
6
|
-
const area = 'artifact-engine';
|
|
6
|
+
const area = 'artifact-engine-v2';
|
|
7
7
|
function getDefaultProps() {
|
|
8
8
|
var hostType = (tl.getVariable('SYSTEM.HOSTTYPE') || "").toLowerCase();
|
|
9
9
|
var isReleaseHost = hostType === 'release' || hostType === "deployment";
|
|
@@ -11,7 +11,7 @@ class BasicCredentialHandler {
|
|
|
11
11
|
// currently implements pre-authorization
|
|
12
12
|
// TODO: support preAuth = false where it hooks on 401
|
|
13
13
|
prepareRequest(options) {
|
|
14
|
-
options.headers['Authorization'] = 'Basic ' +
|
|
14
|
+
options.headers['Authorization'] = 'Basic ' + Buffer.from(this.username + ':' + this.password, 'utf8').toString('base64');
|
|
15
15
|
options.headers['X-TFS-FedAuthRedirect'] = 'Suppress';
|
|
16
16
|
}
|
|
17
17
|
// This handler cannot handle 401
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
// Copyright (c) Microsoft. All rights reserved.
|
|
3
3
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
4
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
5
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
6
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
7
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
8
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
9
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
10
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
11
|
+
});
|
|
12
|
+
};
|
|
4
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
14
|
exports.NtlmCredentialHandler = void 0;
|
|
6
15
|
const http = require("http");
|
|
@@ -91,26 +100,28 @@ class NtlmCredentialHandler {
|
|
|
91
100
|
}
|
|
92
101
|
// The following method is an adaptation of code found at https://github.com/SamDecrock/node-http-ntlm/blob/master/httpntlm.js
|
|
93
102
|
sendType3Message(httpClient, protocol, options, objs, keepaliveAgent, res, callback) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
103
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
104
|
+
if (!res.headers['www-authenticate']) {
|
|
105
|
+
return callback(new Error('www-authenticate not found on response of second request'));
|
|
106
|
+
}
|
|
107
|
+
// parse type2 message from server:
|
|
108
|
+
var type2msg = ntlm.parseType2Message(res.headers['www-authenticate']);
|
|
109
|
+
// create type3 message:
|
|
110
|
+
var type3msg = yield ntlm.createType3Message(type2msg, options);
|
|
111
|
+
// build type3 request:
|
|
112
|
+
var type3options = {
|
|
113
|
+
headers: {
|
|
114
|
+
'Authorization': type3msg
|
|
115
|
+
},
|
|
116
|
+
allowRedirects: false,
|
|
117
|
+
agent: keepaliveAgent
|
|
118
|
+
};
|
|
119
|
+
// pass along other options:
|
|
120
|
+
type3options.headers = _.extend(type3options.headers, options.headers);
|
|
121
|
+
type3options = _.extend(type3options, _.omit(options, 'headers'));
|
|
122
|
+
// send type3 message to server:
|
|
123
|
+
httpClient.requestInternal(protocol, type3options, objs, callback);
|
|
124
|
+
});
|
|
114
125
|
}
|
|
115
126
|
}
|
|
116
127
|
exports.NtlmCredentialHandler = NtlmCredentialHandler;
|
|
@@ -10,7 +10,7 @@ class PersonalAccessTokenCredentialHandler {
|
|
|
10
10
|
// currently implements pre-authorization
|
|
11
11
|
// TODO: support preAuth = false where it hooks on 401
|
|
12
12
|
prepareRequest(options) {
|
|
13
|
-
options.headers['Authorization'] = 'Basic ' +
|
|
13
|
+
options.headers['Authorization'] = 'Basic ' + Buffer.from('PAT:' + this.token, 'utf8').toString('base64');
|
|
14
14
|
options.headers['X-TFS-FedAuthRedirect'] = 'Suppress';
|
|
15
15
|
}
|
|
16
16
|
// This handler cannot handle 401
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var crypto = require('crypto');
|
|
2
|
+
var hashwasm = require('hash-wasm');
|
|
2
3
|
|
|
3
4
|
var flags = {
|
|
4
5
|
NTLM_NegotiateUnicode : 0x00000001,
|
|
@@ -70,7 +71,7 @@ function createType1Message(options){
|
|
|
70
71
|
type1flags = type1flags - flags.NTLM_NegotiateOemDomainSupplied;
|
|
71
72
|
|
|
72
73
|
var pos = 0;
|
|
73
|
-
var buf =
|
|
74
|
+
var buf = Buffer.alloc(BODY_LENGTH + domain.length + workstation.length);
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
buf.write(protocol, pos, protocol.length); pos += protocol.length; // protocol
|
|
@@ -105,7 +106,7 @@ function parseType2Message(rawmsg, callback){
|
|
|
105
106
|
if(!match || !match[1])
|
|
106
107
|
return callback(new Error("Couldn't find NTLM in the message type2 comming from the server"));
|
|
107
108
|
|
|
108
|
-
var buf =
|
|
109
|
+
var buf = Buffer.from(match[1], 'base64');
|
|
109
110
|
|
|
110
111
|
var msg = {};
|
|
111
112
|
|
|
@@ -133,7 +134,7 @@ function parseType2Message(rawmsg, callback){
|
|
|
133
134
|
return msg;
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
function createType3Message(msg2, options){
|
|
137
|
+
async function createType3Message(msg2, options){
|
|
137
138
|
var nonce = msg2.serverChallenge;
|
|
138
139
|
var username = options.username;
|
|
139
140
|
var password = options.password;
|
|
@@ -151,27 +152,27 @@ function createType3Message(msg2, options){
|
|
|
151
152
|
|
|
152
153
|
var encryptedRandomSessionKey = "";
|
|
153
154
|
if(isUnicode){
|
|
154
|
-
workstationBytes =
|
|
155
|
-
domainNameBytes =
|
|
156
|
-
usernameBytes =
|
|
157
|
-
encryptedRandomSessionKeyBytes =
|
|
155
|
+
workstationBytes = Buffer.from(workstation, 'utf16le');
|
|
156
|
+
domainNameBytes = Buffer.from(domainName, 'utf16le');
|
|
157
|
+
usernameBytes = Buffer.from(username, 'utf16le');
|
|
158
|
+
encryptedRandomSessionKeyBytes = Buffer.from(encryptedRandomSessionKey, 'utf16le');
|
|
158
159
|
}else{
|
|
159
|
-
workstationBytes =
|
|
160
|
-
domainNameBytes =
|
|
161
|
-
usernameBytes =
|
|
162
|
-
encryptedRandomSessionKeyBytes =
|
|
160
|
+
workstationBytes = Buffer.from(workstation, 'ascii');
|
|
161
|
+
domainNameBytes = Buffer.from(domainName, 'ascii');
|
|
162
|
+
usernameBytes = Buffer.from(username, 'ascii');
|
|
163
|
+
encryptedRandomSessionKeyBytes = Buffer.from(encryptedRandomSessionKey, 'ascii');
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
var lmChallengeResponse = calc_resp(create_LM_hashed_password_v1(password), nonce);
|
|
166
|
-
var ntChallengeResponse = calc_resp(create_NT_hashed_password_v1(password), nonce);
|
|
167
|
+
var ntChallengeResponse = calc_resp(await create_NT_hashed_password_v1(password), nonce);
|
|
167
168
|
|
|
168
169
|
if(isNegotiateExtendedSecurity){
|
|
169
|
-
var pwhash = create_NT_hashed_password_v1(password);
|
|
170
|
+
var pwhash = await create_NT_hashed_password_v1(password);
|
|
170
171
|
var clientChallenge = "";
|
|
171
172
|
for(var i=0; i < 8; i++){
|
|
172
173
|
clientChallenge += String.fromCharCode( Math.floor(Math.random()*256) );
|
|
173
174
|
}
|
|
174
|
-
var clientChallengeBytes =
|
|
175
|
+
var clientChallengeBytes = Buffer.from(clientChallenge, 'ascii');
|
|
175
176
|
var challenges = ntlm2sr_calc_resp(pwhash, nonce, clientChallengeBytes);
|
|
176
177
|
lmChallengeResponse = challenges.lmChallengeResponse;
|
|
177
178
|
ntChallengeResponse = challenges.ntChallengeResponse;
|
|
@@ -180,7 +181,7 @@ function createType3Message(msg2, options){
|
|
|
180
181
|
var signature = 'NTLMSSP\0';
|
|
181
182
|
|
|
182
183
|
var pos = 0;
|
|
183
|
-
var buf =
|
|
184
|
+
var buf = Buffer.alloc(BODY_LENGTH + domainNameBytes.length + usernameBytes.length + workstationBytes.length + lmChallengeResponse.length + ntChallengeResponse.length + encryptedRandomSessionKeyBytes.length);
|
|
184
185
|
|
|
185
186
|
buf.write(signature, pos, signature.length); pos += signature.length;
|
|
186
187
|
buf.writeUInt32LE(3, pos); pos += 4; // type 1
|
|
@@ -232,9 +233,9 @@ function createType3Message(msg2, options){
|
|
|
232
233
|
function create_LM_hashed_password_v1(password){
|
|
233
234
|
// fix the password length to 14 bytes
|
|
234
235
|
password = password.toUpperCase();
|
|
235
|
-
var passwordBytes =
|
|
236
|
+
var passwordBytes = Buffer.from(password, 'ascii');
|
|
236
237
|
|
|
237
|
-
var passwordBytesPadded =
|
|
238
|
+
var passwordBytesPadded = Buffer.alloc(14);
|
|
238
239
|
passwordBytesPadded.fill("\0");
|
|
239
240
|
var sourceEnd = 14;
|
|
240
241
|
if(passwordBytes.length < 14) sourceEnd = passwordBytes.length;
|
|
@@ -329,23 +330,22 @@ function binaryArray2bytes(array){
|
|
|
329
330
|
var hexchar1 = binary2hex[binString1];
|
|
330
331
|
var hexchar2 = binary2hex[binString2];
|
|
331
332
|
|
|
332
|
-
var buf =
|
|
333
|
+
var buf = Buffer.from(hexchar1 + '' + hexchar2, 'hex');
|
|
333
334
|
bufArray.push(buf);
|
|
334
335
|
}
|
|
335
336
|
|
|
336
337
|
return Buffer.concat(bufArray);
|
|
337
338
|
}
|
|
338
339
|
|
|
339
|
-
function create_NT_hashed_password_v1(password){
|
|
340
|
-
var buf =
|
|
341
|
-
var
|
|
342
|
-
|
|
343
|
-
return new Buffer(md4.digest());
|
|
340
|
+
async function create_NT_hashed_password_v1(password){
|
|
341
|
+
var buf = Buffer.from(password, 'utf16le');
|
|
342
|
+
var hexHash = await hashwasm.md4(buf); // CodeQL [SM04514] [SM01511] Suppress - NTLM requires md4 hashing which is weak but cannot be changed as the protocol does not support stronger algorithms. Using hash-wasm (pure JS/WASM) since crypto.createHash('md4') was removed in Node 17+ (OpenSSL 3.0)
|
|
343
|
+
return Buffer.from(hexHash, 'hex');
|
|
344
344
|
}
|
|
345
345
|
|
|
346
346
|
function calc_resp(password_hash, server_challenge){
|
|
347
347
|
// padding with zeros to make the hash 21 bytes long
|
|
348
|
-
var passHashPadded =
|
|
348
|
+
var passHashPadded = Buffer.alloc(21);
|
|
349
349
|
passHashPadded.fill("\0");
|
|
350
350
|
password_hash.copy(passHashPadded, 0, 0, password_hash.length);
|
|
351
351
|
|
|
@@ -365,7 +365,7 @@ function calc_resp(password_hash, server_challenge){
|
|
|
365
365
|
|
|
366
366
|
function ntlm2sr_calc_resp(responseKeyNT, serverChallenge, clientChallenge){
|
|
367
367
|
// padding with zeros to make the hash 16 bytes longer
|
|
368
|
-
var lmChallengeResponse =
|
|
368
|
+
var lmChallengeResponse = Buffer.alloc(clientChallenge.length + 16);
|
|
369
369
|
lmChallengeResponse.fill("\0");
|
|
370
370
|
clientChallenge.copy(lmChallengeResponse, 0, 0, clientChallenge.length);
|
|
371
371
|
|
|
@@ -383,7 +383,4 @@ function ntlm2sr_calc_resp(responseKeyNT, serverChallenge, clientChallenge){
|
|
|
383
383
|
|
|
384
384
|
exports.createType1Message = createType1Message;
|
|
385
385
|
exports.parseType2Message = parseType2Message;
|
|
386
|
-
exports.createType3Message = createType3Message;
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
386
|
+
exports.createType3Message = createType3Message;
|
|
@@ -47,11 +47,14 @@ class WebClientFactory {
|
|
|
47
47
|
if (lookupKey && lookupKey.indexOf(':') > 0) {
|
|
48
48
|
let lookupInfo = lookupKey.split(':', 2);
|
|
49
49
|
// file contains encryption key
|
|
50
|
-
let keyFile =
|
|
51
|
-
let encryptKey =
|
|
52
|
-
let encryptedContent =
|
|
53
|
-
//
|
|
54
|
-
|
|
50
|
+
let keyFile = Buffer.from(lookupInfo[0], 'base64').toString('utf8');
|
|
51
|
+
let encryptKey = Buffer.from(fs.readFileSync(keyFile, 'utf8'), 'base64');
|
|
52
|
+
let encryptedContent = Buffer.from(lookupInfo[1], 'base64').toString('utf8');
|
|
53
|
+
// Ensure key is 32 bytes for AES-256
|
|
54
|
+
const key = encryptKey.length === 32 ? encryptKey : crypto.createHash('sha256').update(encryptKey).digest();
|
|
55
|
+
// Use zero IV for AES-256-CTR (must match encryption side)
|
|
56
|
+
const iv = Buffer.alloc(16, 0);
|
|
57
|
+
let decipher = crypto.createDecipheriv("aes-256-ctr", key, iv);
|
|
55
58
|
let decryptedContent = decipher.update(encryptedContent, 'hex', 'utf8');
|
|
56
59
|
decryptedContent += decipher.final('utf8');
|
|
57
60
|
return decryptedContent;
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ To use Artifact engine in your tasks or app have a look at [E2E.ts](E2ETests/jen
|
|
|
16
16
|
## Development
|
|
17
17
|
**Build**
|
|
18
18
|
---------
|
|
19
|
-
1. Run npm install in
|
|
19
|
+
1. Run npm install in ArtifactEngineV2 folder
|
|
20
20
|
2. Use command ctrl-shift-b to build from vscode
|
|
21
21
|
|
|
22
22
|
**Testing**
|
|
@@ -30,10 +30,10 @@ To use Artifact engine in your tasks or app have a look at [E2E.ts](E2ETests/jen
|
|
|
30
30
|
------
|
|
31
31
|
1. To run ArtifactEngine integration and unit tests from root directory use
|
|
32
32
|
|
|
33
|
-
`gulp test --suite=
|
|
33
|
+
`gulp test --suite=ArtifactEngineV2`
|
|
34
34
|
2. To run Performance tests update [test config file](test.config.json.example) and rename it to test.config.json and run
|
|
35
35
|
|
|
36
|
-
`gulp test --suite=
|
|
36
|
+
`gulp test --suite=ArtifactEngineV2 --perf`
|
|
37
37
|
3. To run End-to-End tests update [test config file](test.config.json.example) and rename it to test.config.json and run
|
|
38
38
|
|
|
39
|
-
`gulp test --suite=
|
|
39
|
+
`gulp test --suite=ArtifactEngineV2 --e2e`
|
package/lib.json
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
"UnableToReadDirectory": "Unable to read directory %s. Error: %s",
|
|
8
8
|
"RetryingDownload": "Retrying download of %s, retry count: %s",
|
|
9
9
|
"SkippingItem": "Skipped processing item %s",
|
|
10
|
-
"UnhandledRejection": "artifact-engine: unhandled rejection %s",
|
|
11
|
-
"UnhandledException": "artifact-engine: unhandled exception %s",
|
|
10
|
+
"UnhandledRejection": "artifact-engine-v2: unhandled rejection %s",
|
|
11
|
+
"UnhandledException": "artifact-engine-v2: unhandled exception %s",
|
|
12
12
|
"FailedRequest": "Failed request: (statusCode)"
|
|
13
13
|
}
|
|
14
14
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "artifact-engine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.272.0",
|
|
4
4
|
"description": "Artifact Engine to download artifacts from jenkins, teamcity, vsts",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
|
-
"url": "https://github.com/Microsoft/azure-pipelines-extensions/tree/master/Extensions/
|
|
7
|
+
"url": "https://github.com/Microsoft/azure-pipelines-extensions/tree/master/Extensions/ArtifactEngineV2"
|
|
8
8
|
},
|
|
9
9
|
"keywords": [
|
|
10
10
|
"artifact"
|
|
@@ -18,25 +18,23 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"azure-pipelines-task-lib": "^5.2.8",
|
|
20
20
|
"handlebars": "4.7.7",
|
|
21
|
-
"
|
|
21
|
+
"hash-wasm": "^4.12.0",
|
|
22
|
+
"minimatch": "^10.0.1",
|
|
22
23
|
"tunnel": "0.0.4"
|
|
23
24
|
},
|
|
24
|
-
"overrides": {
|
|
25
|
-
"minimatch": "3.1.5"
|
|
26
|
-
},
|
|
27
25
|
"devDependencies": {
|
|
28
|
-
"@types/minimatch": "^
|
|
26
|
+
"@types/minimatch": "^5.1.2",
|
|
29
27
|
"@types/mocha": "^10.0.10",
|
|
30
|
-
"@types/node": "^10.
|
|
28
|
+
"@types/node": "^22.10.5",
|
|
31
29
|
"@types/xml2js": "^0.4.8",
|
|
32
30
|
"assert": "1.4.1",
|
|
33
31
|
"mocha": "^11.7.5",
|
|
34
32
|
"mocha-tap-reporter": "0.1.3",
|
|
35
33
|
"nconf": "^0.12.0",
|
|
36
|
-
"nock": "
|
|
37
|
-
"nyc": "^
|
|
38
|
-
"sinon": "
|
|
39
|
-
"typescript": "
|
|
34
|
+
"nock": "^13.5.6",
|
|
35
|
+
"nyc": "^17.1.0",
|
|
36
|
+
"sinon": "^19.0.2",
|
|
37
|
+
"typescript": "^5.7.2",
|
|
40
38
|
"xml2js": "^0.6.2"
|
|
41
39
|
},
|
|
42
40
|
"files": [
|
|
@@ -56,7 +54,8 @@
|
|
|
56
54
|
"Strings/**"
|
|
57
55
|
],
|
|
58
56
|
"scripts": {
|
|
59
|
-
"test": "
|
|
57
|
+
"test": "mocha",
|
|
58
|
+
"test:coverage": "nyc mocha",
|
|
60
59
|
"build": "tsc"
|
|
61
60
|
}
|
|
62
61
|
}
|