@super-protocol/pki-sync-client 2.0.1 → 2.0.3
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/dist/cli.js +13 -3
- package/dist/sync-client.d.ts +4 -0
- package/dist/sync-client.js +62 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,8 @@ async function sync(argv) {
|
|
|
20
20
|
ownChallenge: argv.ownChallenge,
|
|
21
21
|
verbose: argv.verbose,
|
|
22
22
|
disableServerIdentityCheck: argv.disableServerIdentityCheck,
|
|
23
|
+
saveCertsToDir: argv.saveCertsToDir,
|
|
24
|
+
saveCertsPrefix: argv.saveCertsPrefix,
|
|
23
25
|
});
|
|
24
26
|
await client.sync(config);
|
|
25
27
|
console.log('Sync completed successfully');
|
|
@@ -46,9 +48,9 @@ async function main() {
|
|
|
46
48
|
demandOption: true,
|
|
47
49
|
})
|
|
48
50
|
.option('own-challenge', {
|
|
49
|
-
describe: 'Own challenge string for authentication',
|
|
51
|
+
describe: 'Own challenge string for authentication (auto, tdx, sev, untrusted)',
|
|
50
52
|
type: 'string',
|
|
51
|
-
|
|
53
|
+
default: 'auto',
|
|
52
54
|
})
|
|
53
55
|
.option('verbose', {
|
|
54
56
|
alias: 'v',
|
|
@@ -60,6 +62,14 @@ async function main() {
|
|
|
60
62
|
describe: 'Disable server identity verification',
|
|
61
63
|
type: 'boolean',
|
|
62
64
|
default: false,
|
|
65
|
+
})
|
|
66
|
+
.option('save-certs-to-dir', {
|
|
67
|
+
describe: 'Directory to save client certificates (key.pem, ca.pem, cert.pem)',
|
|
68
|
+
type: 'string',
|
|
69
|
+
})
|
|
70
|
+
.option('save-certs-prefix', {
|
|
71
|
+
describe: 'Prefix for certificate filenames (e.g., "client" -> client_key.pem)',
|
|
72
|
+
type: 'string',
|
|
63
73
|
});
|
|
64
74
|
}, sync)
|
|
65
75
|
.demandCommand(1, 'You must provide a command')
|
|
@@ -73,4 +83,4 @@ main().catch((error) => {
|
|
|
73
83
|
console.error('Error:', error.message);
|
|
74
84
|
process.exit(1);
|
|
75
85
|
});
|
|
76
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
86
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSxrREFBMEI7QUFDMUIsMkNBQXdDO0FBQ3hDLHFDQUFzRDtBQUN0RCwrQ0FBMkM7QUFFM0MsTUFBTSxzQkFBc0IsR0FBRywwQkFBMEIsQ0FBQztBQUUxRCxLQUFLLFVBQVUsSUFBSSxDQUFDLElBQVM7SUFDekIsSUFBSSxDQUFDO1FBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBQSxvQkFBVyxFQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN4QyxNQUFNLFFBQVEsR0FBRyxJQUFBLHNCQUFhLEVBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRTlDLE1BQU0sTUFBTSxHQUFHLElBQUksd0JBQVUsQ0FBQztZQUMxQixPQUFPLEVBQUUsUUFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDLE9BQU87WUFDMUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxlQUFlLENBQUMsQ0FBQyxVQUFVO1lBQ2hELFFBQVEsRUFBRSxRQUFRLENBQUMsZUFBZSxDQUFDLENBQUMsUUFBUTtZQUM1QyxZQUFZLEVBQUUsSUFBSSxDQUFDLFlBQVk7WUFDL0IsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO1lBQ3JCLDBCQUEwQixFQUFFLElBQUksQ0FBQywwQkFBMEI7WUFDM0QsY0FBYyxFQUFFLElBQUksQ0FBQyxjQUFjO1lBQ25DLGVBQWUsRUFBRSxJQUFJLENBQUMsZUFBZTtTQUN4QyxDQUFDLENBQUM7UUFFSCxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFMUIsT0FBTyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1FBQ2xCLE9BQU8sQ0FBQyxLQUFLLENBQUMsY0FBYyxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM3QyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3BCLENBQUM7QUFDTCxDQUFDO0FBRUQsS0FBSyxVQUFVLElBQUk7SUFDZixNQUFNLElBQUEsZUFBSyxFQUFDLElBQUEsaUJBQU8sRUFBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7U0FDN0IsS0FBSyxDQUFDLDBCQUEwQixDQUFDO1NBQ2pDLE9BQU8sQ0FDSixNQUFNLEVBQ04sOEJBQThCLEVBQzlCLENBQUMsS0FBSyxFQUFFLEVBQUU7UUFDTixPQUFPLEtBQUs7YUFDUCxNQUFNLENBQUMsV0FBVyxFQUFFO1lBQ2pCLFFBQVEsRUFBRSx5Q0FBeUM7WUFDbkQsSUFBSSxFQUFFLFFBQVE7WUFDZCxPQUFPLEVBQUUsc0JBQXNCO1NBQ2xDLENBQUM7YUFDRCxNQUFNLENBQUMsUUFBUSxFQUFFO1lBQ2QsS0FBSyxFQUFFLEdBQUc7WUFDVixRQUFRLEVBQUUsb0NBQW9DO1lBQzlDLElBQUksRUFBRSxRQUFRO1lBQ2QsWUFBWSxFQUFFLElBQUk7U0FDckIsQ0FBQzthQUNELE1BQU0sQ0FBQyxlQUFlLEVBQUU7WUFDckIsUUFBUSxFQUNKLHFFQUFxRTtZQUN6RSxJQUFJLEVBQUUsUUFBUTtZQUNkLE9BQU8sRUFBRSxNQUFNO1NBQ2xCLENBQUM7YUFDRCxNQUFNLENBQUMsU0FBUyxFQUFFO1lBQ2YsS0FBSyxFQUFFLEdBQUc7WUFDVixRQUFRLEVBQUUsZ0JBQWdCO1lBQzFCLElBQUksRUFBRSxTQUFTO1lBQ2YsT0FBTyxFQUFFLEtBQUs7U0FDakIsQ0FBQzthQUNELE1BQU0sQ0FBQywrQkFBK0IsRUFBRTtZQUNyQyxRQUFRLEVBQUUsc0NBQXNDO1lBQ2hELElBQUksRUFBRSxTQUFTO1lBQ2YsT0FBTyxFQUFFLEtBQUs7U0FDakIsQ0FBQzthQUNELE1BQU0sQ0FBQyxtQkFBbUIsRUFBRTtZQUN6QixRQUFRLEVBQ0osbUVBQW1FO1lBQ3ZFLElBQUksRUFBRSxRQUFRO1NBQ2pCLENBQUM7YUFDRCxNQUFNLENBQUMsbUJBQW1CLEVBQUU7WUFDekIsUUFBUSxFQUNKLHFFQUFxRTtZQUN6RSxJQUFJLEVBQUUsUUFBUTtTQUNqQixDQUFDLENBQUM7SUFDWCxDQUFDLEVBQ0QsSUFBSSxDQUNQO1NBQ0EsYUFBYSxDQUFDLENBQUMsRUFBRSw0QkFBNEIsQ0FBQztTQUM5QyxJQUFJLEVBQUU7U0FDTixLQUFLLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQztTQUNsQixPQUFPLEVBQUU7U0FDVCxLQUFLLENBQUMsU0FBUyxFQUFFLEdBQUcsQ0FBQztTQUNyQixLQUFLLEVBQUUsQ0FBQztBQUNqQixDQUFDO0FBRUQsSUFBSSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUU7SUFDbkIsT0FBTyxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDcEIsQ0FBQyxDQUFDLENBQUMifQ==
|
package/dist/sync-client.d.ts
CHANGED
|
@@ -6,11 +6,15 @@ export interface SyncClientOptions {
|
|
|
6
6
|
ownChallenge: string;
|
|
7
7
|
verbose?: boolean;
|
|
8
8
|
disableServerIdentityCheck?: boolean;
|
|
9
|
+
saveCertsToDir?: string;
|
|
10
|
+
saveCertsPrefix?: string;
|
|
9
11
|
}
|
|
10
12
|
export declare class SyncClient {
|
|
11
13
|
private options;
|
|
12
14
|
private challenge;
|
|
15
|
+
private static detectCpuType;
|
|
13
16
|
constructor(options: SyncClientOptions);
|
|
14
17
|
private log;
|
|
18
|
+
private saveCertificates;
|
|
15
19
|
sync(config: SyncConfig): Promise<void>;
|
|
16
20
|
}
|
package/dist/sync-client.js
CHANGED
|
@@ -31,18 +31,44 @@ const pki_client_1 = require("@super-protocol/pki-client");
|
|
|
31
31
|
const pki_common_1 = require("@super-protocol/pki-common");
|
|
32
32
|
const axios_1 = __importDefault(require("axios"));
|
|
33
33
|
const fs = __importStar(require("fs"));
|
|
34
|
+
const path = __importStar(require("path"));
|
|
34
35
|
class SyncClient {
|
|
35
36
|
options;
|
|
36
37
|
challenge;
|
|
38
|
+
static detectCpuType() {
|
|
39
|
+
try {
|
|
40
|
+
const tdxPath = '/dev/tdx_guest';
|
|
41
|
+
const sevPath = '/dev/sev-guest';
|
|
42
|
+
if (fs.existsSync(tdxPath)) {
|
|
43
|
+
const stats = fs.statSync(tdxPath);
|
|
44
|
+
if (stats.isCharacterDevice()) {
|
|
45
|
+
return 'tdx';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (fs.existsSync(sevPath)) {
|
|
49
|
+
const stats = fs.statSync(sevPath);
|
|
50
|
+
if (stats.isCharacterDevice()) {
|
|
51
|
+
return 'sev';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// If we can't check devices, fall back to untrusted
|
|
57
|
+
}
|
|
58
|
+
return 'untrusted';
|
|
59
|
+
}
|
|
37
60
|
constructor(options) {
|
|
38
61
|
this.options = options;
|
|
39
|
-
|
|
62
|
+
const challengeType = options.ownChallenge === 'auto'
|
|
63
|
+
? SyncClient.detectCpuType()
|
|
64
|
+
: options.ownChallenge;
|
|
65
|
+
if (challengeType === 'tdx') {
|
|
40
66
|
this.challenge = { type: pki_common_1.ChallengeType.TDX };
|
|
41
67
|
}
|
|
42
|
-
else if (
|
|
68
|
+
else if (challengeType === 'sev') {
|
|
43
69
|
this.challenge = { type: pki_common_1.ChallengeType.SEVSNP };
|
|
44
70
|
}
|
|
45
|
-
else if (
|
|
71
|
+
else if (challengeType === 'untrusted') {
|
|
46
72
|
this.challenge = {
|
|
47
73
|
type: pki_common_1.ChallengeType.Untrusted,
|
|
48
74
|
idHex: 'aaaaaa',
|
|
@@ -50,7 +76,7 @@ class SyncClient {
|
|
|
50
76
|
};
|
|
51
77
|
}
|
|
52
78
|
else {
|
|
53
|
-
throw new Error(`Unsupported challenge type: ${
|
|
79
|
+
throw new Error(`Unsupported challenge type: ${challengeType}. Supported: tdx, sev, untrusted, auto`);
|
|
54
80
|
}
|
|
55
81
|
}
|
|
56
82
|
log(message) {
|
|
@@ -58,6 +84,28 @@ class SyncClient {
|
|
|
58
84
|
console.log(message);
|
|
59
85
|
}
|
|
60
86
|
}
|
|
87
|
+
async saveCertificates(pkiClientFactory, certsDir, prefix) {
|
|
88
|
+
// Ensure directory exists
|
|
89
|
+
if (!fs.existsSync(certsDir)) {
|
|
90
|
+
await fs.promises.mkdir(certsDir, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
const cert = await pkiClientFactory.getCert();
|
|
93
|
+
const { cert: clientCert, intermediateCertificates, ca, } = (0, pki_common_1.extractIntermediateCertificates)(cert);
|
|
94
|
+
const prefixStr = prefix ? `${prefix}_` : '';
|
|
95
|
+
// Save private key
|
|
96
|
+
const keyPath = path.join(certsDir, `${prefixStr}key.pem`);
|
|
97
|
+
await fs.promises.writeFile(keyPath, cert.keyPair.privateKeyPem);
|
|
98
|
+
this.log(`Saved private key to ${keyPath}`);
|
|
99
|
+
// Save CA certificate
|
|
100
|
+
const caPath = path.join(certsDir, `${prefixStr}ca.pem`);
|
|
101
|
+
await fs.promises.writeFile(caPath, ca);
|
|
102
|
+
this.log(`Saved CA certificate to ${caPath}`);
|
|
103
|
+
// Save client certificate with intermediate chain
|
|
104
|
+
const certWithIntermediate = clientCert + intermediateCertificates;
|
|
105
|
+
const certPath = path.join(certsDir, `${prefixStr}cert.pem`);
|
|
106
|
+
await fs.promises.writeFile(certPath, certWithIntermediate);
|
|
107
|
+
this.log(`Saved certificate chain to ${certPath}`);
|
|
108
|
+
}
|
|
61
109
|
async sync(config) {
|
|
62
110
|
for (const server of this.options.servers) {
|
|
63
111
|
try {
|
|
@@ -86,9 +134,18 @@ class SyncClient {
|
|
|
86
134
|
throw new Error(`Secret "${secret.secretName}" not found in response`);
|
|
87
135
|
}
|
|
88
136
|
const content = Buffer.from(base64Content, 'base64');
|
|
137
|
+
// Ensure directory exists
|
|
138
|
+
const dir = path.dirname(secret.saveTo);
|
|
139
|
+
if (!fs.existsSync(dir)) {
|
|
140
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
141
|
+
}
|
|
89
142
|
await fs.promises.writeFile(secret.saveTo, content);
|
|
90
143
|
this.log(`Saved secret "${secret.secretName}" to ${secret.saveTo}`);
|
|
91
144
|
}
|
|
145
|
+
// Save certificates if directory is specified
|
|
146
|
+
if (this.options.saveCertsToDir) {
|
|
147
|
+
await this.saveCertificates(pkiClientFactory, this.options.saveCertsToDir, this.options.saveCertsPrefix);
|
|
148
|
+
}
|
|
92
149
|
this.log(`Successfully synced from server: ${server}`);
|
|
93
150
|
return; // Success - exit from method
|
|
94
151
|
}
|
|
@@ -101,4 +158,4 @@ class SyncClient {
|
|
|
101
158
|
}
|
|
102
159
|
}
|
|
103
160
|
exports.SyncClient = SyncClient;
|
|
104
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
161
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3luYy1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvc3luYy1jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFDQSwyREFJb0M7QUFDcEMsMkRBR29DO0FBQ3BDLGtEQUEwQjtBQUMxQix1Q0FBeUI7QUFDekIsMkNBQTZCO0FBYTdCLE1BQWEsVUFBVTtJQUNYLE9BQU8sQ0FBb0I7SUFDM0IsU0FBUyxDQUFrQjtJQUUzQixNQUFNLENBQUMsYUFBYTtRQUN4QixJQUFJLENBQUM7WUFDRCxNQUFNLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQztZQUNqQyxNQUFNLE9BQU8sR0FBRyxnQkFBZ0IsQ0FBQztZQUVqQyxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDekIsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDbkMsSUFBSSxLQUFLLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDO29CQUM1QixPQUFPLEtBQUssQ0FBQztnQkFDakIsQ0FBQztZQUNMLENBQUM7WUFFRCxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDekIsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDbkMsSUFBSSxLQUFLLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxDQUFDO29CQUM1QixPQUFPLEtBQUssQ0FBQztnQkFDakIsQ0FBQztZQUNMLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNiLG9EQUFvRDtRQUN4RCxDQUFDO1FBRUQsT0FBTyxXQUFXLENBQUM7SUFDdkIsQ0FBQztJQUVELFlBQVksT0FBMEI7UUFDbEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFFdkIsTUFBTSxh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
|