@dishantlangayan/sc-cli-core 0.5.3 → 0.7.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/lib/auth/auth-encryption.d.ts +6 -5
- package/lib/auth/auth-encryption.js +14 -8
- package/lib/auth/auth-types.d.ts +0 -70
- package/lib/auth/auth-types.js +1 -41
- package/lib/auth/{auth-manager.d.ts → broker-auth-manager.d.ts} +15 -1
- package/lib/auth/{auth-manager.js → broker-auth-manager.js} +64 -24
- package/lib/auth/broker-auth-types.d.ts +57 -0
- package/lib/auth/broker-auth-types.js +40 -0
- package/lib/auth/index.d.ts +4 -3
- package/lib/auth/index.js +3 -3
- package/lib/auth/org-manager.js +8 -8
- package/lib/exported.d.ts +1 -1
- package/lib/sc-command.d.ts +1 -1
- package/lib/sc-command.js +1 -1
- package/package.json +1 -1
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { EncryptedData } from './auth-types.js';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Generic encryption utility for authentication storage
|
|
4
4
|
* Uses AES-256-GCM for authenticated encryption
|
|
5
|
+
* Can be used by both OrgManager and BrokerAuthManager
|
|
5
6
|
*/
|
|
6
|
-
export declare class
|
|
7
|
+
export declare class AuthEncryption {
|
|
7
8
|
private static readonly ALGORITHM;
|
|
8
9
|
private static readonly DIGEST;
|
|
9
10
|
private static readonly ITERATIONS;
|
|
@@ -17,7 +18,7 @@ export declare class BrokerAuthEncryption {
|
|
|
17
18
|
* @param key - Decryption key
|
|
18
19
|
* @returns Decrypted storage
|
|
19
20
|
*/
|
|
20
|
-
static decrypt<T
|
|
21
|
+
static decrypt<T>(encryptedData: EncryptedData, key: Buffer): Promise<T>;
|
|
21
22
|
/**
|
|
22
23
|
* Derive encryption key from password using PBKDF2
|
|
23
24
|
* @param password - User password
|
|
@@ -31,7 +32,7 @@ export declare class BrokerAuthEncryption {
|
|
|
31
32
|
* @param key - Encryption key
|
|
32
33
|
* @returns Encrypted data with metadata
|
|
33
34
|
*/
|
|
34
|
-
static encrypt<T
|
|
35
|
+
static encrypt<T>(data: T, key: Buffer): Promise<EncryptedData>;
|
|
35
36
|
/**
|
|
36
37
|
* Generate cryptographically secure random salt
|
|
37
38
|
* @returns Random salt buffer
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createCipheriv, createDecipheriv, pbkdf2, randomBytes } from 'node:crypto';
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
|
-
import { BrokerAuthError, BrokerAuthErrorCode } from './auth-types.js';
|
|
4
3
|
const pbkdf2Async = promisify(pbkdf2);
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
5
|
+
* Generic encryption utility for authentication storage
|
|
7
6
|
* Uses AES-256-GCM for authenticated encryption
|
|
7
|
+
* Can be used by both OrgManager and BrokerAuthManager
|
|
8
8
|
*/
|
|
9
|
-
export class
|
|
9
|
+
export class AuthEncryption {
|
|
10
10
|
static ALGORITHM = 'aes-256-gcm';
|
|
11
11
|
static DIGEST = 'sha256';
|
|
12
12
|
static ITERATIONS = 100_000; // OWASP recommended minimum for PBKDF2
|
|
@@ -36,7 +36,9 @@ export class BrokerAuthEncryption {
|
|
|
36
36
|
return storage;
|
|
37
37
|
}
|
|
38
38
|
catch (error) {
|
|
39
|
-
|
|
39
|
+
const err = new Error('Failed to decrypt storage. The password may be incorrect or the file may be corrupted.');
|
|
40
|
+
err.cause = error;
|
|
41
|
+
throw err;
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
/**
|
|
@@ -48,15 +50,17 @@ export class BrokerAuthEncryption {
|
|
|
48
50
|
static async deriveKey(password, salt) {
|
|
49
51
|
try {
|
|
50
52
|
if (!password || password.length === 0) {
|
|
51
|
-
throw new
|
|
53
|
+
throw new Error('Password cannot be empty');
|
|
52
54
|
}
|
|
53
55
|
return await pbkdf2Async(password, salt, this.ITERATIONS, this.KEY_LENGTH, this.DIGEST);
|
|
54
56
|
}
|
|
55
57
|
catch (error) {
|
|
56
|
-
if (error instanceof
|
|
58
|
+
if (error instanceof Error && error.message === 'Password cannot be empty') {
|
|
57
59
|
throw error;
|
|
58
60
|
}
|
|
59
|
-
|
|
61
|
+
const err = new Error('Failed to derive encryption key');
|
|
62
|
+
err.cause = error;
|
|
63
|
+
throw err;
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
/**
|
|
@@ -93,7 +97,9 @@ export class BrokerAuthEncryption {
|
|
|
93
97
|
};
|
|
94
98
|
}
|
|
95
99
|
catch (error) {
|
|
96
|
-
|
|
100
|
+
const err = new Error('Failed to encrypt storage');
|
|
101
|
+
err.cause = error;
|
|
102
|
+
throw err;
|
|
97
103
|
}
|
|
98
104
|
}
|
|
99
105
|
/**
|
package/lib/auth/auth-types.d.ts
CHANGED
|
@@ -1,46 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Authentication types supported by the broker auth system
|
|
3
|
-
*/
|
|
4
|
-
export declare enum AuthType {
|
|
5
|
-
BASIC = "basic",
|
|
6
|
-
OAUTH = "oauth"
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Base broker authentication configuration
|
|
10
|
-
*/
|
|
11
|
-
export interface BrokerAuthBase {
|
|
12
|
-
authType: AuthType;
|
|
13
|
-
name: string;
|
|
14
|
-
sempEndpoint: string;
|
|
15
|
-
sempPort: number;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* OAuth broker authentication configuration
|
|
19
|
-
*/
|
|
20
|
-
export interface OAuthBrokerAuth extends BrokerAuthBase {
|
|
21
|
-
accessToken: string;
|
|
22
|
-
authType: AuthType.OAUTH;
|
|
23
|
-
clientId: string;
|
|
24
|
-
refreshToken: string;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Basic authentication broker configuration
|
|
28
|
-
*/
|
|
29
|
-
export interface BasicBrokerAuth extends BrokerAuthBase {
|
|
30
|
-
authType: AuthType.BASIC;
|
|
31
|
-
encodedCredentials: string;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Union type for broker authentication
|
|
35
|
-
*/
|
|
36
|
-
export type BrokerAuth = BasicBrokerAuth | OAuthBrokerAuth;
|
|
37
|
-
/**
|
|
38
|
-
* Storage format for broker configurations
|
|
39
|
-
*/
|
|
40
|
-
export interface BrokerAuthStorage {
|
|
41
|
-
brokers: BrokerAuth[];
|
|
42
|
-
version: string;
|
|
43
|
-
}
|
|
44
1
|
/**
|
|
45
2
|
* Encryption metadata stored alongside encrypted data
|
|
46
3
|
*/
|
|
@@ -60,30 +17,3 @@ export interface EncryptedData {
|
|
|
60
17
|
metadata: EncryptionMetadata;
|
|
61
18
|
salt: string;
|
|
62
19
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Error codes for broker auth operations
|
|
65
|
-
*/
|
|
66
|
-
export declare enum BrokerAuthErrorCode {
|
|
67
|
-
BROKER_ALREADY_EXISTS = "BROKER_ALREADY_EXISTS",
|
|
68
|
-
BROKER_NOT_FOUND = "BROKER_NOT_FOUND",
|
|
69
|
-
DECRYPTION_FAILED = "DECRYPTION_FAILED",
|
|
70
|
-
ENCRYPTION_FAILED = "ENCRYPTION_FAILED",
|
|
71
|
-
FILE_READ_ERROR = "FILE_READ_ERROR",
|
|
72
|
-
FILE_WRITE_ERROR = "FILE_WRITE_ERROR",
|
|
73
|
-
INVALID_AUTH_TYPE = "INVALID_AUTH_TYPE",
|
|
74
|
-
INVALID_BASIC_CONFIG = "INVALID_BASIC_CONFIG",
|
|
75
|
-
INVALID_ENDPOINT = "INVALID_ENDPOINT",
|
|
76
|
-
INVALID_NAME = "INVALID_NAME",
|
|
77
|
-
INVALID_OAUTH_CONFIG = "INVALID_OAUTH_CONFIG",
|
|
78
|
-
INVALID_PASSWORD = "INVALID_PASSWORD",
|
|
79
|
-
INVALID_PORT = "INVALID_PORT",
|
|
80
|
-
NOT_INITIALIZED = "NOT_INITIALIZED"
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Custom error class for broker authentication operations
|
|
84
|
-
*/
|
|
85
|
-
export declare class BrokerAuthError extends Error {
|
|
86
|
-
readonly code: BrokerAuthErrorCode;
|
|
87
|
-
readonly cause?: Error | undefined;
|
|
88
|
-
constructor(message: string, code: BrokerAuthErrorCode, cause?: Error | undefined);
|
|
89
|
-
}
|
package/lib/auth/auth-types.js
CHANGED
|
@@ -1,41 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Authentication types supported by the broker auth system
|
|
3
|
-
*/
|
|
4
|
-
export var AuthType;
|
|
5
|
-
(function (AuthType) {
|
|
6
|
-
AuthType["BASIC"] = "basic";
|
|
7
|
-
AuthType["OAUTH"] = "oauth";
|
|
8
|
-
})(AuthType || (AuthType = {}));
|
|
9
|
-
/**
|
|
10
|
-
* Error codes for broker auth operations
|
|
11
|
-
*/
|
|
12
|
-
export var BrokerAuthErrorCode;
|
|
13
|
-
(function (BrokerAuthErrorCode) {
|
|
14
|
-
BrokerAuthErrorCode["BROKER_ALREADY_EXISTS"] = "BROKER_ALREADY_EXISTS";
|
|
15
|
-
BrokerAuthErrorCode["BROKER_NOT_FOUND"] = "BROKER_NOT_FOUND";
|
|
16
|
-
BrokerAuthErrorCode["DECRYPTION_FAILED"] = "DECRYPTION_FAILED";
|
|
17
|
-
BrokerAuthErrorCode["ENCRYPTION_FAILED"] = "ENCRYPTION_FAILED";
|
|
18
|
-
BrokerAuthErrorCode["FILE_READ_ERROR"] = "FILE_READ_ERROR";
|
|
19
|
-
BrokerAuthErrorCode["FILE_WRITE_ERROR"] = "FILE_WRITE_ERROR";
|
|
20
|
-
BrokerAuthErrorCode["INVALID_AUTH_TYPE"] = "INVALID_AUTH_TYPE";
|
|
21
|
-
BrokerAuthErrorCode["INVALID_BASIC_CONFIG"] = "INVALID_BASIC_CONFIG";
|
|
22
|
-
BrokerAuthErrorCode["INVALID_ENDPOINT"] = "INVALID_ENDPOINT";
|
|
23
|
-
BrokerAuthErrorCode["INVALID_NAME"] = "INVALID_NAME";
|
|
24
|
-
BrokerAuthErrorCode["INVALID_OAUTH_CONFIG"] = "INVALID_OAUTH_CONFIG";
|
|
25
|
-
BrokerAuthErrorCode["INVALID_PASSWORD"] = "INVALID_PASSWORD";
|
|
26
|
-
BrokerAuthErrorCode["INVALID_PORT"] = "INVALID_PORT";
|
|
27
|
-
BrokerAuthErrorCode["NOT_INITIALIZED"] = "NOT_INITIALIZED";
|
|
28
|
-
})(BrokerAuthErrorCode || (BrokerAuthErrorCode = {}));
|
|
29
|
-
/**
|
|
30
|
-
* Custom error class for broker authentication operations
|
|
31
|
-
*/
|
|
32
|
-
export class BrokerAuthError extends Error {
|
|
33
|
-
code;
|
|
34
|
-
cause;
|
|
35
|
-
constructor(message, code, cause) {
|
|
36
|
-
super(message);
|
|
37
|
-
this.code = code;
|
|
38
|
-
this.cause = cause;
|
|
39
|
-
this.name = 'BrokerAuthError';
|
|
40
|
-
}
|
|
41
|
-
}
|
|
1
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ScConnection } from '../util/sc-connection.js';
|
|
2
|
-
import { type BrokerAuth } from './auth-types.js';
|
|
2
|
+
import { type BrokerAuth } from './broker-auth-types.js';
|
|
3
3
|
import { KeychainService } from './keychain.js';
|
|
4
4
|
/**
|
|
5
5
|
* Manager for broker authentication storage
|
|
@@ -53,6 +53,11 @@ export declare class BrokerAuthManager {
|
|
|
53
53
|
* @returns Broker configuration or null if not found
|
|
54
54
|
*/
|
|
55
55
|
getBroker(name: string): Promise<BrokerAuth | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Get the default broker
|
|
58
|
+
* @returns Default broker or null if no default is set
|
|
59
|
+
*/
|
|
60
|
+
getDefaultBroker(): Promise<BrokerAuth | null>;
|
|
56
61
|
/**
|
|
57
62
|
* Initialize the auth manager with encryption key derived from OS keychain and machine ID
|
|
58
63
|
*/
|
|
@@ -67,6 +72,11 @@ export declare class BrokerAuthManager {
|
|
|
67
72
|
* @param name - Broker name to remove
|
|
68
73
|
*/
|
|
69
74
|
removeBroker(name: string): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Set a broker as the default
|
|
77
|
+
* @param name - Broker name to set as default
|
|
78
|
+
*/
|
|
79
|
+
setDefaultBroker(name: string): Promise<void>;
|
|
70
80
|
/**
|
|
71
81
|
* Update existing broker configuration
|
|
72
82
|
* @param name - Broker name to update
|
|
@@ -90,6 +100,10 @@ export declare class BrokerAuthManager {
|
|
|
90
100
|
* Save storage to encrypted file
|
|
91
101
|
*/
|
|
92
102
|
private saveStorage;
|
|
103
|
+
/**
|
|
104
|
+
* Unset the default flag on all brokers
|
|
105
|
+
*/
|
|
106
|
+
private unsetAllDefaults;
|
|
93
107
|
/**
|
|
94
108
|
* Validate broker configuration
|
|
95
109
|
* @param broker - Broker to validate
|
|
@@ -2,8 +2,8 @@ import { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { ScConnection } from '../util/sc-connection.js';
|
|
5
|
-
import {
|
|
6
|
-
import { AuthType, BrokerAuthError, BrokerAuthErrorCode, } from './auth-types.js';
|
|
5
|
+
import { AuthEncryption } from './auth-encryption.js';
|
|
6
|
+
import { AuthType, BrokerAuthError, BrokerAuthErrorCode, } from './broker-auth-types.js';
|
|
7
7
|
import { KeychainService } from './keychain.js';
|
|
8
8
|
const SERVICE_NAME = 'local';
|
|
9
9
|
const KEY_NAME = 'sc-cli';
|
|
@@ -49,6 +49,10 @@ export class BrokerAuthManager {
|
|
|
49
49
|
if (existing) {
|
|
50
50
|
throw new BrokerAuthError(`Broker '${broker.name}' already exists`, BrokerAuthErrorCode.BROKER_ALREADY_EXISTS);
|
|
51
51
|
}
|
|
52
|
+
// If this broker is being set as default, unset any existing default
|
|
53
|
+
if (broker.isDefault) {
|
|
54
|
+
this.unsetAllDefaults();
|
|
55
|
+
}
|
|
52
56
|
// Add broker
|
|
53
57
|
this.storage.brokers.push(broker);
|
|
54
58
|
// Save to file
|
|
@@ -84,7 +88,7 @@ export class BrokerAuthManager {
|
|
|
84
88
|
throw new BrokerAuthError(`Broker '${brokerName}' not found`, BrokerAuthErrorCode.BROKER_NOT_FOUND);
|
|
85
89
|
}
|
|
86
90
|
const baseURL = `${broker.sempEndpoint}:${broker.sempPort}`;
|
|
87
|
-
const accessToken = broker
|
|
91
|
+
const { accessToken } = broker;
|
|
88
92
|
return new ScConnection(baseURL, accessToken, {
|
|
89
93
|
apiType: 'semp',
|
|
90
94
|
authType: broker.authType === AuthType.BASIC ? 'basic' : 'bearer',
|
|
@@ -109,6 +113,15 @@ export class BrokerAuthManager {
|
|
|
109
113
|
const broker = this.storage.brokers.find((b) => b.name === name);
|
|
110
114
|
return broker ?? null;
|
|
111
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Get the default broker
|
|
118
|
+
* @returns Default broker or null if no default is set
|
|
119
|
+
*/
|
|
120
|
+
async getDefaultBroker() {
|
|
121
|
+
this.ensureInitialized();
|
|
122
|
+
const broker = this.storage.brokers.find((b) => b.isDefault === true);
|
|
123
|
+
return broker ?? null;
|
|
124
|
+
}
|
|
112
125
|
/**
|
|
113
126
|
* Initialize the auth manager with encryption key derived from OS keychain and machine ID
|
|
114
127
|
*/
|
|
@@ -133,8 +146,8 @@ export class BrokerAuthManager {
|
|
|
133
146
|
}
|
|
134
147
|
else {
|
|
135
148
|
// Create new storage with new salt
|
|
136
|
-
const salt =
|
|
137
|
-
this.encryptionKey = await
|
|
149
|
+
const salt = AuthEncryption.generateSalt();
|
|
150
|
+
this.encryptionKey = await AuthEncryption.deriveKey(combinedKey, salt);
|
|
138
151
|
this.storage = {
|
|
139
152
|
brokers: [],
|
|
140
153
|
version: '1.0.0',
|
|
@@ -171,6 +184,23 @@ export class BrokerAuthManager {
|
|
|
171
184
|
// Save to file
|
|
172
185
|
await this.saveStorage();
|
|
173
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Set a broker as the default
|
|
189
|
+
* @param name - Broker name to set as default
|
|
190
|
+
*/
|
|
191
|
+
async setDefaultBroker(name) {
|
|
192
|
+
this.ensureInitialized();
|
|
193
|
+
const index = this.storage.brokers.findIndex((b) => b.name === name);
|
|
194
|
+
if (index === -1) {
|
|
195
|
+
throw new BrokerAuthError(`Broker '${name}' not found`, BrokerAuthErrorCode.BROKER_NOT_FOUND);
|
|
196
|
+
}
|
|
197
|
+
// Unset all existing defaults
|
|
198
|
+
this.unsetAllDefaults();
|
|
199
|
+
// Set this broker as default
|
|
200
|
+
this.storage.brokers[index].isDefault = true;
|
|
201
|
+
// Save to file
|
|
202
|
+
await this.saveStorage();
|
|
203
|
+
}
|
|
174
204
|
/**
|
|
175
205
|
* Update existing broker configuration
|
|
176
206
|
* @param name - Broker name to update
|
|
@@ -182,6 +212,10 @@ export class BrokerAuthManager {
|
|
|
182
212
|
if (index === -1) {
|
|
183
213
|
throw new BrokerAuthError(`Broker '${name}' not found`, BrokerAuthErrorCode.BROKER_NOT_FOUND);
|
|
184
214
|
}
|
|
215
|
+
// If setting this broker as default, unset any existing default
|
|
216
|
+
if (updates.isDefault === true) {
|
|
217
|
+
this.unsetAllDefaults();
|
|
218
|
+
}
|
|
185
219
|
// Merge updates
|
|
186
220
|
const updated = {
|
|
187
221
|
...this.storage.brokers[index],
|
|
@@ -225,9 +259,9 @@ export class BrokerAuthManager {
|
|
|
225
259
|
const encryptedData = JSON.parse(fileContent);
|
|
226
260
|
// Derive key from combined key and stored salt
|
|
227
261
|
const salt = Buffer.from(encryptedData.salt, 'base64');
|
|
228
|
-
this.encryptionKey = await
|
|
262
|
+
this.encryptionKey = await AuthEncryption.deriveKey(combinedKey, salt);
|
|
229
263
|
// Decrypt storage
|
|
230
|
-
this.storage = await
|
|
264
|
+
this.storage = await AuthEncryption.decrypt(encryptedData, this.encryptionKey);
|
|
231
265
|
}
|
|
232
266
|
catch (error) {
|
|
233
267
|
if (error instanceof BrokerAuthError) {
|
|
@@ -246,12 +280,16 @@ export class BrokerAuthManager {
|
|
|
246
280
|
}
|
|
247
281
|
// Ensure directory exists
|
|
248
282
|
await mkdir(this.configDir, { mode: 0o700, recursive: true });
|
|
249
|
-
//
|
|
250
|
-
const encrypted = await BrokerAuthEncryption.encrypt(this.storage, this.encryptionKey);
|
|
251
|
-
// Re-derive key with new salt for next save
|
|
283
|
+
// Generate new salt and derive key for THIS save
|
|
252
284
|
const combinedKey = `${this.masterKey}:${this.machineId}`;
|
|
253
|
-
const newSalt =
|
|
254
|
-
|
|
285
|
+
const newSalt = AuthEncryption.generateSalt();
|
|
286
|
+
const newKey = await AuthEncryption.deriveKey(combinedKey, newSalt);
|
|
287
|
+
// Encrypt data with the new key
|
|
288
|
+
const encrypted = await AuthEncryption.encrypt(this.storage, newKey);
|
|
289
|
+
// Update the salt in encrypted data to match the salt we used for key derivation
|
|
290
|
+
encrypted.salt = newSalt.toString('base64');
|
|
291
|
+
// Store the new key for next operation
|
|
292
|
+
this.encryptionKey = newKey;
|
|
255
293
|
// Write to temp file first (atomic write)
|
|
256
294
|
const jsonData = JSON.stringify(encrypted, null, 2);
|
|
257
295
|
const tempFile = `${this.configFile}.tmp`;
|
|
@@ -277,6 +315,14 @@ export class BrokerAuthManager {
|
|
|
277
315
|
throw new BrokerAuthError('Failed to save broker storage', BrokerAuthErrorCode.FILE_WRITE_ERROR, error);
|
|
278
316
|
}
|
|
279
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Unset the default flag on all brokers
|
|
320
|
+
*/
|
|
321
|
+
unsetAllDefaults() {
|
|
322
|
+
for (const broker of this.storage.brokers) {
|
|
323
|
+
broker.isDefault = false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
280
326
|
/**
|
|
281
327
|
* Validate broker configuration
|
|
282
328
|
* @param broker - Broker to validate
|
|
@@ -294,19 +340,13 @@ export class BrokerAuthManager {
|
|
|
294
340
|
if (broker.sempPort < 1 || broker.sempPort > 65_535) {
|
|
295
341
|
throw new BrokerAuthError('SEMP port must be between 1 and 65535', BrokerAuthErrorCode.INVALID_PORT);
|
|
296
342
|
}
|
|
297
|
-
// Validate auth
|
|
298
|
-
if (broker.authType
|
|
299
|
-
if (!broker.accessToken || !broker.clientId) {
|
|
300
|
-
throw new BrokerAuthError('OAuth brokers require accessToken and clientId', BrokerAuthErrorCode.INVALID_OAUTH_CONFIG);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
else if (broker.authType === AuthType.BASIC) {
|
|
304
|
-
if (!broker.encodedCredentials) {
|
|
305
|
-
throw new BrokerAuthError('Basic auth brokers require encodedCredentials', BrokerAuthErrorCode.INVALID_BASIC_CONFIG);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
343
|
+
// Validate auth type
|
|
344
|
+
if (broker.authType !== AuthType.OAUTH && broker.authType !== AuthType.BASIC) {
|
|
309
345
|
throw new BrokerAuthError('Invalid auth type', BrokerAuthErrorCode.INVALID_AUTH_TYPE);
|
|
310
346
|
}
|
|
347
|
+
// Validate access token
|
|
348
|
+
if (!broker.accessToken || broker.accessToken.trim() === '') {
|
|
349
|
+
throw new BrokerAuthError('Access token is required', BrokerAuthErrorCode.INVALID_ACCESS_TOKEN);
|
|
350
|
+
}
|
|
311
351
|
}
|
|
312
352
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication types supported by the broker auth system
|
|
3
|
+
*/
|
|
4
|
+
export declare enum AuthType {
|
|
5
|
+
BASIC = "basic",
|
|
6
|
+
OAUTH = "oauth"
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Broker authentication configuration
|
|
10
|
+
*
|
|
11
|
+
* @property {string} accessToken - For OAuth: access token string. For Basic: base64-encoded credentials
|
|
12
|
+
* @property {AuthType} authType - Type of authentication (BASIC or OAUTH)
|
|
13
|
+
* @property {string} name - Human-readable name/alias for the broker
|
|
14
|
+
* @property {string} sempEndpoint - SEMP endpoint URL (must start with http:// or https://)
|
|
15
|
+
* @property {number} sempPort - SEMP port number (1-65535)
|
|
16
|
+
*/
|
|
17
|
+
export interface BrokerAuth {
|
|
18
|
+
accessToken: string;
|
|
19
|
+
authType: AuthType;
|
|
20
|
+
isDefault?: boolean;
|
|
21
|
+
name: string;
|
|
22
|
+
sempEndpoint: string;
|
|
23
|
+
sempPort: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Storage format for broker configurations
|
|
27
|
+
*/
|
|
28
|
+
export interface BrokerAuthStorage {
|
|
29
|
+
brokers: BrokerAuth[];
|
|
30
|
+
version: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Error codes for broker auth operations
|
|
34
|
+
*/
|
|
35
|
+
export declare enum BrokerAuthErrorCode {
|
|
36
|
+
BROKER_ALREADY_EXISTS = "BROKER_ALREADY_EXISTS",
|
|
37
|
+
BROKER_NOT_FOUND = "BROKER_NOT_FOUND",
|
|
38
|
+
DECRYPTION_FAILED = "DECRYPTION_FAILED",
|
|
39
|
+
ENCRYPTION_FAILED = "ENCRYPTION_FAILED",
|
|
40
|
+
FILE_READ_ERROR = "FILE_READ_ERROR",
|
|
41
|
+
FILE_WRITE_ERROR = "FILE_WRITE_ERROR",
|
|
42
|
+
INVALID_ACCESS_TOKEN = "INVALID_ACCESS_TOKEN",
|
|
43
|
+
INVALID_AUTH_TYPE = "INVALID_AUTH_TYPE",
|
|
44
|
+
INVALID_ENDPOINT = "INVALID_ENDPOINT",
|
|
45
|
+
INVALID_NAME = "INVALID_NAME",
|
|
46
|
+
INVALID_PASSWORD = "INVALID_PASSWORD",
|
|
47
|
+
INVALID_PORT = "INVALID_PORT",
|
|
48
|
+
NOT_INITIALIZED = "NOT_INITIALIZED"
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Custom error class for broker authentication operations
|
|
52
|
+
*/
|
|
53
|
+
export declare class BrokerAuthError extends Error {
|
|
54
|
+
readonly code: BrokerAuthErrorCode;
|
|
55
|
+
readonly cause?: Error | undefined;
|
|
56
|
+
constructor(message: string, code: BrokerAuthErrorCode, cause?: Error | undefined);
|
|
57
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication types supported by the broker auth system
|
|
3
|
+
*/
|
|
4
|
+
export var AuthType;
|
|
5
|
+
(function (AuthType) {
|
|
6
|
+
AuthType["BASIC"] = "basic";
|
|
7
|
+
AuthType["OAUTH"] = "oauth";
|
|
8
|
+
})(AuthType || (AuthType = {}));
|
|
9
|
+
/**
|
|
10
|
+
* Error codes for broker auth operations
|
|
11
|
+
*/
|
|
12
|
+
export var BrokerAuthErrorCode;
|
|
13
|
+
(function (BrokerAuthErrorCode) {
|
|
14
|
+
BrokerAuthErrorCode["BROKER_ALREADY_EXISTS"] = "BROKER_ALREADY_EXISTS";
|
|
15
|
+
BrokerAuthErrorCode["BROKER_NOT_FOUND"] = "BROKER_NOT_FOUND";
|
|
16
|
+
BrokerAuthErrorCode["DECRYPTION_FAILED"] = "DECRYPTION_FAILED";
|
|
17
|
+
BrokerAuthErrorCode["ENCRYPTION_FAILED"] = "ENCRYPTION_FAILED";
|
|
18
|
+
BrokerAuthErrorCode["FILE_READ_ERROR"] = "FILE_READ_ERROR";
|
|
19
|
+
BrokerAuthErrorCode["FILE_WRITE_ERROR"] = "FILE_WRITE_ERROR";
|
|
20
|
+
BrokerAuthErrorCode["INVALID_ACCESS_TOKEN"] = "INVALID_ACCESS_TOKEN";
|
|
21
|
+
BrokerAuthErrorCode["INVALID_AUTH_TYPE"] = "INVALID_AUTH_TYPE";
|
|
22
|
+
BrokerAuthErrorCode["INVALID_ENDPOINT"] = "INVALID_ENDPOINT";
|
|
23
|
+
BrokerAuthErrorCode["INVALID_NAME"] = "INVALID_NAME";
|
|
24
|
+
BrokerAuthErrorCode["INVALID_PASSWORD"] = "INVALID_PASSWORD";
|
|
25
|
+
BrokerAuthErrorCode["INVALID_PORT"] = "INVALID_PORT";
|
|
26
|
+
BrokerAuthErrorCode["NOT_INITIALIZED"] = "NOT_INITIALIZED";
|
|
27
|
+
})(BrokerAuthErrorCode || (BrokerAuthErrorCode = {}));
|
|
28
|
+
/**
|
|
29
|
+
* Custom error class for broker authentication operations
|
|
30
|
+
*/
|
|
31
|
+
export class BrokerAuthError extends Error {
|
|
32
|
+
code;
|
|
33
|
+
cause;
|
|
34
|
+
constructor(message, code, cause) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.code = code;
|
|
37
|
+
this.cause = cause;
|
|
38
|
+
this.name = 'BrokerAuthError';
|
|
39
|
+
}
|
|
40
|
+
}
|
package/lib/auth/index.d.ts
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Authentication management module
|
|
3
3
|
* Provides encrypted storage for broker and organization credentials
|
|
4
4
|
*/
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
5
|
+
export { AuthEncryption } from './auth-encryption.js';
|
|
6
|
+
export { type EncryptedData, type EncryptionMetadata } from './auth-types.js';
|
|
7
|
+
export { BrokerAuthManager } from './broker-auth-manager.js';
|
|
8
|
+
export { AuthType, type BrokerAuth, BrokerAuthError, BrokerAuthErrorCode, type BrokerAuthStorage, } from './broker-auth-types.js';
|
|
8
9
|
export { OrgManager } from './org-manager.js';
|
|
9
10
|
export { type OrgConfig, OrgError, OrgErrorCode, type OrgStorage } from './org-types.js';
|
package/lib/auth/index.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Authentication management module
|
|
3
3
|
* Provides encrypted storage for broker and organization credentials
|
|
4
4
|
*/
|
|
5
|
-
export {
|
|
6
|
-
export { BrokerAuthManager } from './auth-manager.js';
|
|
7
|
-
export { AuthType, BrokerAuthError, BrokerAuthErrorCode, } from './auth-types.js';
|
|
5
|
+
export { AuthEncryption } from './auth-encryption.js';
|
|
6
|
+
export { BrokerAuthManager } from './broker-auth-manager.js';
|
|
7
|
+
export { AuthType, BrokerAuthError, BrokerAuthErrorCode, } from './broker-auth-types.js';
|
|
8
8
|
export { OrgManager } from './org-manager.js';
|
|
9
9
|
export { OrgError, OrgErrorCode } from './org-types.js';
|
package/lib/auth/org-manager.js
CHANGED
|
@@ -3,7 +3,7 @@ import { homedir } from 'node:os';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { DefaultBaseUrl, EnvironmentVariable, envVars } from '../config/env-vars.js';
|
|
5
5
|
import { ScConnection } from '../util/sc-connection.js';
|
|
6
|
-
import {
|
|
6
|
+
import { AuthEncryption } from './auth-encryption.js';
|
|
7
7
|
import { KeychainService } from './keychain.js';
|
|
8
8
|
import { OrgError, OrgErrorCode } from './org-types.js';
|
|
9
9
|
const SERVICE_NAME = 'local';
|
|
@@ -151,8 +151,8 @@ export class OrgManager {
|
|
|
151
151
|
}
|
|
152
152
|
else {
|
|
153
153
|
// Create new storage with new salt
|
|
154
|
-
const salt =
|
|
155
|
-
this.encryptionKey = await
|
|
154
|
+
const salt = AuthEncryption.generateSalt();
|
|
155
|
+
this.encryptionKey = await AuthEncryption.deriveKey(combinedKey, salt);
|
|
156
156
|
this.storage = {
|
|
157
157
|
orgs: [],
|
|
158
158
|
version: '1.0.0',
|
|
@@ -280,9 +280,9 @@ export class OrgManager {
|
|
|
280
280
|
const encryptedData = JSON.parse(fileContent);
|
|
281
281
|
// Derive key from combined key and stored salt
|
|
282
282
|
const salt = Buffer.from(encryptedData.salt, 'base64');
|
|
283
|
-
this.encryptionKey = await
|
|
283
|
+
this.encryptionKey = await AuthEncryption.deriveKey(combinedKey, salt);
|
|
284
284
|
// Decrypt storage
|
|
285
|
-
this.storage = await
|
|
285
|
+
this.storage = await AuthEncryption.decrypt(encryptedData, this.encryptionKey);
|
|
286
286
|
}
|
|
287
287
|
catch (error) {
|
|
288
288
|
if (error instanceof OrgError) {
|
|
@@ -316,10 +316,10 @@ export class OrgManager {
|
|
|
316
316
|
await mkdir(this.configDir, { mode: 0o700, recursive: true });
|
|
317
317
|
// Generate new salt and derive key for THIS save
|
|
318
318
|
const combinedKey = `${this.masterKey}:${this.machineId}`;
|
|
319
|
-
const newSalt =
|
|
320
|
-
const newKey = await
|
|
319
|
+
const newSalt = AuthEncryption.generateSalt();
|
|
320
|
+
const newKey = await AuthEncryption.deriveKey(combinedKey, newSalt);
|
|
321
321
|
// Encrypt data with the new key
|
|
322
|
-
const encrypted = await
|
|
322
|
+
const encrypted = await AuthEncryption.encrypt(this.storage, newKey);
|
|
323
323
|
// Update the salt in encrypted data to match the salt we used for key derivation
|
|
324
324
|
encrypted.salt = newSalt.toString('base64');
|
|
325
325
|
// Store the new key for next operation
|
package/lib/exported.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { AuthType, type
|
|
1
|
+
export { AuthType, type BrokerAuth, BrokerAuthError, BrokerAuthErrorCode, BrokerAuthManager, type OrgConfig, OrgError, OrgErrorCode, OrgManager, type OrgStorage, } from './auth/index.js';
|
|
2
2
|
export { EnvironmentVariable, envVars } from './config/env-vars.js';
|
|
3
3
|
export { ScCommand } from './sc-command.js';
|
|
4
4
|
export { type ApiType, type HttpAuthType, ScConnection, type ScConnectionOptions } from './util/sc-connection.js';
|
package/lib/sc-command.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, Interfaces } from '@oclif/core';
|
|
2
|
-
import { BrokerAuthManager } from './auth/auth-manager.js';
|
|
2
|
+
import { BrokerAuthManager } from './auth/broker-auth-manager.js';
|
|
3
3
|
import { OrgManager } from './auth/org-manager.js';
|
|
4
4
|
export type Flags<T extends typeof Command> = Interfaces.InferredFlags<(typeof ScCommand)['baseFlags'] & T['flags']>;
|
|
5
5
|
export type Args<T extends typeof Command> = Interfaces.InferredArgs<T['args']>;
|
package/lib/sc-command.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
|
-
import { BrokerAuthManager } from './auth/auth-manager.js';
|
|
2
|
+
import { BrokerAuthManager } from './auth/broker-auth-manager.js';
|
|
3
3
|
import { OrgManager } from './auth/org-manager.js';
|
|
4
4
|
/**
|
|
5
5
|
* A base command that provided common functionality for all sc commands.
|