maven-proxy 1.0.1 → 1.0.2

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.
@@ -1,289 +1,383 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import os from "node:os";
4
- import { spawnSync } from "node:child_process";
5
-
6
- const SUPPORTED_STORE_TYPES = new Set(["JKS", "PKCS12"]);
7
-
8
- function runCommand(command, args) {
9
- const result = spawnSync(command, args, {
10
- stdio: "inherit",
11
- shell: false,
12
- });
13
-
14
- if (result.error) {
15
- throw result.error;
16
- }
17
-
18
- if (result.status !== 0) {
19
- throw new Error(`Command failed: ${command} ${args.join(" ")}`);
20
- }
21
- }
22
-
23
- function runCommandCapture(command, args) {
24
- const result = spawnSync(command, args, {
25
- shell: false,
26
- encoding: "utf8",
27
- });
28
-
29
- if (result.error) {
30
- throw result.error;
31
- }
32
-
33
- if (result.status !== 0) {
34
- const stderr = (result.stderr || "").trim();
35
- throw new Error(
36
- stderr || `Command failed: ${command} ${args.join(" ")}`,
37
- );
38
- }
39
-
40
- return result.stdout || "";
41
- }
42
-
43
- export function assertKeytoolAvailable() {
44
- const result = spawnSync("keytool", ["-help"], {
45
- shell: false,
46
- encoding: "utf8",
47
- });
48
-
49
- if (result.error) {
50
- throw new Error(`keytool is not available: ${result.error.message}`);
51
- }
52
-
53
- if (result.status !== 0) {
54
- const stderr = (result.stderr || "").trim();
55
- throw new Error(stderr || "keytool is not available.");
56
- }
57
- }
58
-
59
- function getDefaultCacertsPath(javaHome) {
60
- return path.join(javaHome, "lib", "security", "cacerts");
61
- }
62
-
63
- function parseAliasesFromListOutput(output) {
64
- const aliases = new Set();
65
- const verboseMatches = output.matchAll(/Alias name:\s*(.+)\s*$/gm);
66
- for (const match of verboseMatches) {
67
- aliases.add(match[1].trim());
68
- }
69
-
70
- if (aliases.size > 0) {
71
- return aliases;
72
- }
73
-
74
- // Fallback for non-verbose list format: "<alias>, <date>, <entryType>, ..."
75
- const listMatches = output.matchAll(/^([^,\r\n]+),\s.+$/gm);
76
- for (const match of listMatches) {
77
- aliases.add(match[1].trim());
78
- }
79
-
80
- return aliases;
81
- }
82
-
83
- function listTrustStoreAliases({ storePath, storePass, storeType }) {
84
- const output = runCommandCapture("keytool", [
85
- "-list",
86
- "-v",
87
- "-keystore",
88
- storePath,
89
- "-storepass",
90
- storePass,
91
- "-storetype",
92
- storeType,
93
- ]);
94
-
95
- return parseAliasesFromListOutput(output);
96
- }
97
-
98
- function validateMergeOptions(options) {
99
- if (!options || typeof options !== "object") {
100
- throw new Error("Merge options are required.");
101
- }
102
-
103
- const required = ["sourcePath", "targetPath", "sourcePassword", "targetPassword"];
104
- for (const key of required) {
105
- if (!options[key]) {
106
- throw new Error(`Missing required option: ${key}`);
107
- }
108
- }
109
-
110
- const sourceType = String(options.sourceType || "JKS").toUpperCase();
111
- const targetType = String(options.targetType || "JKS").toUpperCase();
112
-
113
- if (!SUPPORTED_STORE_TYPES.has(sourceType)) {
114
- throw new Error(`Invalid sourceType: ${sourceType}. Use JKS or PKCS12.`);
115
- }
116
-
117
- if (!SUPPORTED_STORE_TYPES.has(targetType)) {
118
- throw new Error(`Invalid targetType: ${targetType}. Use JKS or PKCS12.`);
119
- }
120
-
121
- const resolvedSourcePath = path.resolve(options.sourcePath);
122
- const resolvedTargetPath = path.resolve(options.targetPath);
123
-
124
- if (resolvedSourcePath === resolvedTargetPath) {
125
- throw new Error("sourcePath and targetPath must be different.");
126
- }
127
-
128
- if (!fs.existsSync(options.sourcePath)) {
129
- throw new Error(`Source truststore not found: ${options.sourcePath}`);
130
- }
131
-
132
- const sourceStats = fs.statSync(options.sourcePath);
133
- if (!sourceStats.isFile()) {
134
- throw new Error(`Source truststore is not a file: ${options.sourcePath}`);
135
- }
136
-
137
- if (fs.existsSync(options.targetPath)) {
138
- const targetStats = fs.statSync(options.targetPath);
139
- if (!targetStats.isFile()) {
140
- throw new Error(`Target truststore path is not a file: ${options.targetPath}`);
141
- }
142
- }
143
-
144
- const mode = options.onConflict || "fail";
145
- if (!["fail", "overwrite"].includes(mode)) {
146
- throw new Error(`Invalid onConflict mode: ${mode}. Use \"fail\" or \"overwrite\".`);
147
- }
148
-
149
- return {
150
- onConflict: mode,
151
- sourceType,
152
- targetType,
153
- };
154
- }
155
-
156
- export function getTrustStoreCommands(runtimeConfig) {
157
- const isWindows = os.platform() === "win32";
158
- const javaHome = runtimeConfig.javaHome || (isWindows ? "%JAVA_HOME%" : "$JAVA_HOME");
159
- const defaultCacerts = isWindows
160
- ? `${javaHome}\\lib\\security\\cacerts`
161
- : `${javaHome}/lib/security/cacerts`;
162
-
163
- const copyCmd = isWindows
164
- ? `Copy-Item "${defaultCacerts}" "${runtimeConfig.trustStorePath}"`
165
- : `cp "${defaultCacerts}" "${runtimeConfig.trustStorePath}"`;
166
-
167
- const importCmd = `keytool -importcert -noprompt -trustcacerts -alias "${runtimeConfig.trustStoreAlias}" -file "${runtimeConfig.rootCertPath}" -keystore "${runtimeConfig.trustStorePath}" -storepass "${runtimeConfig.trustStorePassword}"`;
168
- const listCmd = `keytool -list -v -keystore "${runtimeConfig.trustStorePath}" -storepass "${runtimeConfig.trustStorePassword}" -alias "${runtimeConfig.trustStoreAlias}"`;
169
-
170
- return { copyCmd, importCmd, listCmd };
171
- }
172
-
173
- export function initTrustStore(runtimeConfig) {
174
- assertKeytoolAvailable();
175
-
176
- if (!runtimeConfig || !runtimeConfig.javaHome) {
177
- throw new Error("JAVA_HOME is required to initialize trust store.");
178
- }
179
-
180
- const defaultCacerts = getDefaultCacertsPath(runtimeConfig.javaHome);
181
-
182
- if (!fs.existsSync(defaultCacerts)) {
183
- throw new Error(`JDK cacerts not found: ${defaultCacerts}`);
184
- }
185
-
186
- if (!fs.existsSync(runtimeConfig.rootCertPath)) {
187
- throw new Error(`Root certificate not found: ${runtimeConfig.rootCertPath}`);
188
- }
189
-
190
- fs.mkdirSync(path.dirname(runtimeConfig.trustStorePath), { recursive: true });
191
-
192
- if (!fs.existsSync(runtimeConfig.trustStorePath)) {
193
- fs.copyFileSync(defaultCacerts, runtimeConfig.trustStorePath);
194
- }
195
-
196
- runCommand("keytool", [
197
- "-importcert",
198
- "-noprompt",
199
- "-trustcacerts",
200
- "-alias",
201
- runtimeConfig.trustStoreAlias,
202
- "-file",
203
- runtimeConfig.rootCertPath,
204
- "-keystore",
205
- runtimeConfig.trustStorePath,
206
- "-storepass",
207
- runtimeConfig.trustStorePassword,
208
- ]);
209
-
210
- runCommand("keytool", [
211
- "-list",
212
- "-v",
213
- "-keystore",
214
- runtimeConfig.trustStorePath,
215
- "-storepass",
216
- runtimeConfig.trustStorePassword,
217
- "-alias",
218
- runtimeConfig.trustStoreAlias,
219
- ]);
220
- }
221
-
222
- export function mergeTrustStores(options) {
223
- assertKeytoolAvailable();
224
-
225
- const validated = validateMergeOptions(options);
226
- const onConflict = validated.onConflict;
227
- const sourceType = validated.sourceType;
228
- const targetType = validated.targetType;
229
- const dryRun = Boolean(options.dryRun);
230
-
231
- if (!dryRun) {
232
- fs.mkdirSync(path.dirname(options.targetPath), { recursive: true });
233
- }
234
-
235
- if (onConflict === "fail" && fs.existsSync(options.targetPath)) {
236
- const sourceAliases = listTrustStoreAliases({
237
- storePath: options.sourcePath,
238
- storePass: options.sourcePassword,
239
- storeType: sourceType,
240
- });
241
- const targetAliases = listTrustStoreAliases({
242
- storePath: options.targetPath,
243
- storePass: options.targetPassword,
244
- storeType: targetType,
245
- });
246
-
247
- const conflicts = [...sourceAliases].filter((alias) => targetAliases.has(alias));
248
- if (conflicts.length > 0) {
249
- throw new Error(
250
- `Alias conflict detected: ${conflicts.join(", ")}. Use --on-conflict overwrite to continue.`,
251
- );
252
- }
253
- }
254
-
255
- if (dryRun) {
256
- return {
257
- dryRun: true,
258
- checkedSource: options.sourcePath,
259
- checkedTarget: options.targetPath,
260
- onConflict,
261
- sourceType,
262
- targetType,
263
- targetExists: fs.existsSync(options.targetPath),
264
- };
265
- }
266
-
267
- const args = [
268
- "-importkeystore",
269
- "-srckeystore",
270
- options.sourcePath,
271
- "-srcstoretype",
272
- sourceType,
273
- "-srcstorepass",
274
- options.sourcePassword,
275
- "-destkeystore",
276
- options.targetPath,
277
- "-deststoretype",
278
- targetType,
279
- "-deststorepass",
280
- options.targetPassword,
281
- ];
282
-
283
- if (onConflict === "overwrite") {
284
- args.push("-noprompt");
285
- }
286
-
287
- runCommand("keytool", args);
288
- }
289
-
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import os from "node:os";
4
+ import { spawnSync } from "node:child_process";
5
+
6
+ const SUPPORTED_STORE_TYPES = new Set(["JKS", "PKCS12"]);
7
+
8
+ function runCommand(command, args) {
9
+ const result = spawnSync(command, args, {
10
+ stdio: "inherit",
11
+ shell: false,
12
+ });
13
+
14
+ if (result.error) {
15
+ throw result.error;
16
+ }
17
+
18
+ if (result.status !== 0) {
19
+ throw new Error(`Command failed: ${command} ${args.join(" ")}`);
20
+ }
21
+ }
22
+
23
+ function runCommandCapture(command, args) {
24
+ const result = spawnSync(command, args, {
25
+ shell: false,
26
+ encoding: "utf8",
27
+ });
28
+
29
+ if (result.error) {
30
+ throw result.error;
31
+ }
32
+
33
+ if (result.status !== 0) {
34
+ const stderr = (result.stderr || "").trim();
35
+ throw new Error(
36
+ stderr || `Command failed: ${command} ${args.join(" ")}`,
37
+ );
38
+ }
39
+
40
+ return result.stdout || "";
41
+ }
42
+
43
+ function runCommandBestEffort(command, args) {
44
+ const result = spawnSync(command, args, {
45
+ shell: false,
46
+ encoding: "utf8",
47
+ });
48
+
49
+ if (result.error) {
50
+ throw result.error;
51
+ }
52
+
53
+ return result.status === 0;
54
+ }
55
+
56
+ export function assertKeytoolAvailable() {
57
+ const result = spawnSync("keytool", ["-help"], {
58
+ shell: false,
59
+ encoding: "utf8",
60
+ });
61
+
62
+ if (result.error) {
63
+ throw new Error(`keytool is not available: ${result.error.message}`);
64
+ }
65
+
66
+ if (result.status !== 0) {
67
+ const stderr = (result.stderr || "").trim();
68
+ throw new Error(stderr || "keytool is not available.");
69
+ }
70
+ }
71
+
72
+ function getDefaultCacertsPath(javaHome) {
73
+ return path.join(javaHome, "lib", "security", "cacerts");
74
+ }
75
+
76
+ function getExistingStoreSource(runtimeConfig) {
77
+ const sourcePath = String(runtimeConfig.existingTrustStorePath || "").trim();
78
+ if (!sourcePath) {
79
+ return null;
80
+ }
81
+
82
+ if (!fs.existsSync(sourcePath)) {
83
+ return null;
84
+ }
85
+
86
+ const stats = fs.statSync(sourcePath);
87
+ if (!stats.isFile()) {
88
+ throw new Error(`Configured existing truststore is not a file: ${sourcePath}`);
89
+ }
90
+
91
+ return {
92
+ sourcePath,
93
+ sourcePassword: runtimeConfig.existingTrustStorePassword || runtimeConfig.trustStorePassword,
94
+ sourceLabel: "existing truststore",
95
+ };
96
+ }
97
+
98
+ function getJdkStoreSource(runtimeConfig) {
99
+ if (!runtimeConfig || !runtimeConfig.javaHome) {
100
+ throw new Error("JAVA_HOME is required when existing truststore is not available.");
101
+ }
102
+
103
+ const sourcePath = getDefaultCacertsPath(runtimeConfig.javaHome);
104
+ if (!fs.existsSync(sourcePath)) {
105
+ throw new Error(`JDK cacerts not found: ${sourcePath}`);
106
+ }
107
+
108
+ return {
109
+ sourcePath,
110
+ sourcePassword: "changeit",
111
+ sourceLabel: "jdk cacerts",
112
+ };
113
+ }
114
+
115
+ function syncStoreToTarget(sourcePath, targetPath) {
116
+ const samePath = path.resolve(sourcePath) === path.resolve(targetPath);
117
+ if (samePath) {
118
+ return;
119
+ }
120
+
121
+ fs.copyFileSync(sourcePath, targetPath);
122
+ }
123
+
124
+ function ensureTargetStorePassword(targetPath, currentPassword, desiredPassword) {
125
+ if (currentPassword === desiredPassword) {
126
+ return;
127
+ }
128
+
129
+ runCommand("keytool", [
130
+ "-storepasswd",
131
+ "-new",
132
+ desiredPassword,
133
+ "-keystore",
134
+ targetPath,
135
+ "-storepass",
136
+ currentPassword,
137
+ ]);
138
+ }
139
+
140
+ function parseAliasesFromListOutput(output) {
141
+ const aliases = new Set();
142
+ const verboseMatches = output.matchAll(/Alias name:\s*(.+)\s*$/gm);
143
+ for (const match of verboseMatches) {
144
+ aliases.add(match[1].trim());
145
+ }
146
+
147
+ if (aliases.size > 0) {
148
+ return aliases;
149
+ }
150
+
151
+ // Fallback for non-verbose list format: "<alias>, <date>, <entryType>, ..."
152
+ const listMatches = output.matchAll(/^([^,\r\n]+),\s.+$/gm);
153
+ for (const match of listMatches) {
154
+ aliases.add(match[1].trim());
155
+ }
156
+
157
+ return aliases;
158
+ }
159
+
160
+ function listTrustStoreAliases({ storePath, storePass, storeType }) {
161
+ const args = [
162
+ "-list",
163
+ "-v",
164
+ "-keystore",
165
+ storePath,
166
+ "-storepass",
167
+ storePass,
168
+ ];
169
+
170
+ if (storeType) {
171
+ args.push("-storetype", storeType);
172
+ }
173
+
174
+ const output = runCommandCapture("keytool", args);
175
+
176
+ return parseAliasesFromListOutput(output);
177
+ }
178
+
179
+ function validateMergeOptions(options) {
180
+ if (!options || typeof options !== "object") {
181
+ throw new Error("Merge options are required.");
182
+ }
183
+
184
+ const required = ["sourcePath", "targetPath", "sourcePassword", "targetPassword"];
185
+ for (const key of required) {
186
+ if (!options[key]) {
187
+ throw new Error(`Missing required option: ${key}`);
188
+ }
189
+ }
190
+
191
+ const sourceType = String(options.sourceType || "JKS").toUpperCase();
192
+ const targetType = String(options.targetType || "JKS").toUpperCase();
193
+
194
+ if (!SUPPORTED_STORE_TYPES.has(sourceType)) {
195
+ throw new Error(`Invalid sourceType: ${sourceType}. Use JKS or PKCS12.`);
196
+ }
197
+
198
+ if (!SUPPORTED_STORE_TYPES.has(targetType)) {
199
+ throw new Error(`Invalid targetType: ${targetType}. Use JKS or PKCS12.`);
200
+ }
201
+
202
+ const resolvedSourcePath = path.resolve(options.sourcePath);
203
+ const resolvedTargetPath = path.resolve(options.targetPath);
204
+
205
+ if (resolvedSourcePath === resolvedTargetPath) {
206
+ throw new Error("sourcePath and targetPath must be different.");
207
+ }
208
+
209
+ if (!fs.existsSync(options.sourcePath)) {
210
+ throw new Error(`Source truststore not found: ${options.sourcePath}`);
211
+ }
212
+
213
+ const sourceStats = fs.statSync(options.sourcePath);
214
+ if (!sourceStats.isFile()) {
215
+ throw new Error(`Source truststore is not a file: ${options.sourcePath}`);
216
+ }
217
+
218
+ if (fs.existsSync(options.targetPath)) {
219
+ const targetStats = fs.statSync(options.targetPath);
220
+ if (!targetStats.isFile()) {
221
+ throw new Error(`Target truststore path is not a file: ${options.targetPath}`);
222
+ }
223
+ }
224
+
225
+ const mode = options.onConflict || "fail";
226
+ if (!["fail", "overwrite"].includes(mode)) {
227
+ throw new Error(`Invalid onConflict mode: ${mode}. Use \"fail\" or \"overwrite\".`);
228
+ }
229
+
230
+ return {
231
+ onConflict: mode,
232
+ sourceType,
233
+ targetType,
234
+ };
235
+ }
236
+
237
+ export function getTrustStoreCommands(runtimeConfig) {
238
+ const isWindows = os.platform() === "win32";
239
+ const javaHome = runtimeConfig.javaHome || (isWindows ? "%JAVA_HOME%" : "$JAVA_HOME");
240
+ const defaultCacerts = isWindows
241
+ ? `${javaHome}\\lib\\security\\cacerts`
242
+ : `${javaHome}/lib/security/cacerts`;
243
+
244
+ const existingStore = String(runtimeConfig.existingTrustStorePath || "").trim();
245
+ const copySource = existingStore && fs.existsSync(existingStore)
246
+ ? existingStore
247
+ : defaultCacerts;
248
+ const copyCmd = isWindows
249
+ ? `Copy-Item "${copySource}" "${runtimeConfig.trustStorePath}"`
250
+ : `cp "${copySource}" "${runtimeConfig.trustStorePath}"`;
251
+
252
+ const importCmd = `keytool -importcert -noprompt -trustcacerts -alias "${runtimeConfig.trustStoreAlias}" -file "${runtimeConfig.rootCertPath}" -keystore "${runtimeConfig.trustStorePath}" -storepass "${runtimeConfig.trustStorePassword}"`;
253
+ const listCmd = `keytool -list -v -keystore "${runtimeConfig.trustStorePath}" -storepass "${runtimeConfig.trustStorePassword}" -alias "${runtimeConfig.trustStoreAlias}"`;
254
+
255
+ return { copyCmd, importCmd, listCmd };
256
+ }
257
+
258
+ export function initTrustStore(runtimeConfig) {
259
+ assertKeytoolAvailable();
260
+
261
+ if (!fs.existsSync(runtimeConfig.rootCertPath)) {
262
+ throw new Error(`Root certificate not found: ${runtimeConfig.rootCertPath}`);
263
+ }
264
+
265
+ fs.mkdirSync(path.dirname(runtimeConfig.trustStorePath), { recursive: true });
266
+
267
+ const existingSource = getExistingStoreSource(runtimeConfig);
268
+ const source = existingSource || getJdkStoreSource(runtimeConfig);
269
+
270
+ syncStoreToTarget(source.sourcePath, runtimeConfig.trustStorePath);
271
+ ensureTargetStorePassword(
272
+ runtimeConfig.trustStorePath,
273
+ source.sourcePassword,
274
+ runtimeConfig.trustStorePassword,
275
+ );
276
+
277
+ console.log(`[truststore] source: ${source.sourceLabel} (${source.sourcePath})`);
278
+ console.log(`[truststore] output: ${runtimeConfig.trustStorePath}`);
279
+
280
+ runCommandBestEffort("keytool", [
281
+ "-delete",
282
+ "-alias",
283
+ runtimeConfig.trustStoreAlias,
284
+ "-keystore",
285
+ runtimeConfig.trustStorePath,
286
+ "-storepass",
287
+ runtimeConfig.trustStorePassword,
288
+ ]);
289
+
290
+ runCommand("keytool", [
291
+ "-importcert",
292
+ "-noprompt",
293
+ "-trustcacerts",
294
+ "-alias",
295
+ runtimeConfig.trustStoreAlias,
296
+ "-file",
297
+ runtimeConfig.rootCertPath,
298
+ "-keystore",
299
+ runtimeConfig.trustStorePath,
300
+ "-storepass",
301
+ runtimeConfig.trustStorePassword,
302
+ ]);
303
+
304
+ runCommand("keytool", [
305
+ "-list",
306
+ "-v",
307
+ "-keystore",
308
+ runtimeConfig.trustStorePath,
309
+ "-storepass",
310
+ runtimeConfig.trustStorePassword,
311
+ "-alias",
312
+ runtimeConfig.trustStoreAlias,
313
+ ]);
314
+ }
315
+
316
+ export function mergeTrustStores(options) {
317
+ assertKeytoolAvailable();
318
+
319
+ const validated = validateMergeOptions(options);
320
+ const onConflict = validated.onConflict;
321
+ const sourceType = validated.sourceType;
322
+ const targetType = validated.targetType;
323
+ const dryRun = Boolean(options.dryRun);
324
+
325
+ if (!dryRun) {
326
+ fs.mkdirSync(path.dirname(options.targetPath), { recursive: true });
327
+ }
328
+
329
+ if (onConflict === "fail" && fs.existsSync(options.targetPath)) {
330
+ const sourceAliases = listTrustStoreAliases({
331
+ storePath: options.sourcePath,
332
+ storePass: options.sourcePassword,
333
+ storeType: sourceType,
334
+ });
335
+ const targetAliases = listTrustStoreAliases({
336
+ storePath: options.targetPath,
337
+ storePass: options.targetPassword,
338
+ storeType: targetType,
339
+ });
340
+
341
+ const conflicts = [...sourceAliases].filter((alias) => targetAliases.has(alias));
342
+ if (conflicts.length > 0) {
343
+ throw new Error(
344
+ `Alias conflict detected: ${conflicts.join(", ")}. Use --on-conflict overwrite to continue.`,
345
+ );
346
+ }
347
+ }
348
+
349
+ if (dryRun) {
350
+ return {
351
+ dryRun: true,
352
+ checkedSource: options.sourcePath,
353
+ checkedTarget: options.targetPath,
354
+ onConflict,
355
+ sourceType,
356
+ targetType,
357
+ targetExists: fs.existsSync(options.targetPath),
358
+ };
359
+ }
360
+
361
+ const args = [
362
+ "-importkeystore",
363
+ "-srckeystore",
364
+ options.sourcePath,
365
+ "-srcstoretype",
366
+ sourceType,
367
+ "-srcstorepass",
368
+ options.sourcePassword,
369
+ "-destkeystore",
370
+ options.targetPath,
371
+ "-deststoretype",
372
+ targetType,
373
+ "-deststorepass",
374
+ options.targetPassword,
375
+ ];
376
+
377
+ if (onConflict === "overwrite") {
378
+ args.push("-noprompt");
379
+ }
380
+
381
+ runCommand("keytool", args);
382
+ }
383
+