@dishantlangayan/sc-cli-core 0.1.2 → 0.3.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/README.md +3 -0
- package/lib/auth/auth-encryption.d.ts +40 -0
- package/lib/auth/auth-encryption.js +106 -0
- package/lib/auth/auth-manager.d.ts +98 -0
- package/lib/auth/auth-manager.js +309 -0
- package/lib/auth/auth-types.d.ts +89 -0
- package/lib/auth/auth-types.js +41 -0
- package/lib/auth/index.d.ts +7 -0
- package/lib/auth/index.js +7 -0
- package/lib/auth/keychain.d.ts +47 -0
- package/lib/auth/keychain.js +71 -0
- package/lib/exported.d.ts +1 -0
- package/lib/exported.js +1 -0
- package/lib/util/sc-connection.d.ts +1 -1
- package/lib/util/sc-connection.js +3 -3
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -20,6 +20,9 @@ The ScCommand abstract class extends [@oclif/core's Command class](https://githu
|
|
|
20
20
|
## ScConnection Class
|
|
21
21
|
The ScConnection class provide abstraction functions for Solace Cloud API REST calls. It handles the access token and base URL for each REST call, avoiding the need to set these on each Command.
|
|
22
22
|
|
|
23
|
+
## BrokerAuthManager
|
|
24
|
+
The BrokerAuthManager class provides utility functions to store and retrieve broker SEMP management authentication information from user's home directory: `~/.sf/` or `%USERPROFILE%\sf\`. The implementation uses AES-256-GCM for authenticated encryption and provides machine-bound encryption that combines OS-level security (keychain) with machine-specific identifiers, making credentials non-transferable between machines.
|
|
25
|
+
|
|
23
26
|
# Contributing
|
|
24
27
|
Contributions are encouraged! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us.
|
|
25
28
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type BrokerAuthStorage, type EncryptedData } from './auth-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Encryption utility for broker authentication storage
|
|
4
|
+
* Uses AES-256-GCM for authenticated encryption
|
|
5
|
+
*/
|
|
6
|
+
export declare class BrokerAuthEncryption {
|
|
7
|
+
private static readonly ALGORITHM;
|
|
8
|
+
private static readonly DIGEST;
|
|
9
|
+
private static readonly ITERATIONS;
|
|
10
|
+
private static readonly IV_LENGTH;
|
|
11
|
+
private static readonly KEY_LENGTH;
|
|
12
|
+
private static readonly SALT_LENGTH;
|
|
13
|
+
private static readonly TAG_LENGTH;
|
|
14
|
+
/**
|
|
15
|
+
* Decrypt broker storage data
|
|
16
|
+
* @param encryptedData - Encrypted data to decrypt
|
|
17
|
+
* @param key - Decryption key
|
|
18
|
+
* @returns Decrypted broker storage
|
|
19
|
+
*/
|
|
20
|
+
static decrypt(encryptedData: EncryptedData, key: Buffer): Promise<BrokerAuthStorage>;
|
|
21
|
+
/**
|
|
22
|
+
* Derive encryption key from password using PBKDF2
|
|
23
|
+
* @param password - User password
|
|
24
|
+
* @param salt - Salt for key derivation
|
|
25
|
+
* @returns Derived encryption key
|
|
26
|
+
*/
|
|
27
|
+
static deriveKey(password: string, salt: Buffer): Promise<Buffer>;
|
|
28
|
+
/**
|
|
29
|
+
* Encrypt broker storage data
|
|
30
|
+
* @param data - Broker storage to encrypt
|
|
31
|
+
* @param key - Encryption key
|
|
32
|
+
* @returns Encrypted data with metadata
|
|
33
|
+
*/
|
|
34
|
+
static encrypt(data: BrokerAuthStorage, key: Buffer): Promise<EncryptedData>;
|
|
35
|
+
/**
|
|
36
|
+
* Generate cryptographically secure random salt
|
|
37
|
+
* @returns Random salt buffer
|
|
38
|
+
*/
|
|
39
|
+
static generateSalt(): Buffer;
|
|
40
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, pbkdf2, randomBytes } from 'node:crypto';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { BrokerAuthError, BrokerAuthErrorCode } from './auth-types.js';
|
|
4
|
+
const pbkdf2Async = promisify(pbkdf2);
|
|
5
|
+
/**
|
|
6
|
+
* Encryption utility for broker authentication storage
|
|
7
|
+
* Uses AES-256-GCM for authenticated encryption
|
|
8
|
+
*/
|
|
9
|
+
export class BrokerAuthEncryption {
|
|
10
|
+
static ALGORITHM = 'aes-256-gcm';
|
|
11
|
+
static DIGEST = 'sha256';
|
|
12
|
+
static ITERATIONS = 100_000; // OWASP recommended minimum for PBKDF2
|
|
13
|
+
static IV_LENGTH = 16;
|
|
14
|
+
static KEY_LENGTH = 32; // 256 bits
|
|
15
|
+
static SALT_LENGTH = 32;
|
|
16
|
+
static TAG_LENGTH = 16;
|
|
17
|
+
/**
|
|
18
|
+
* Decrypt broker storage data
|
|
19
|
+
* @param encryptedData - Encrypted data to decrypt
|
|
20
|
+
* @param key - Decryption key
|
|
21
|
+
* @returns Decrypted broker storage
|
|
22
|
+
*/
|
|
23
|
+
static async decrypt(encryptedData, key) {
|
|
24
|
+
try {
|
|
25
|
+
// Parse metadata and buffers
|
|
26
|
+
const iv = Buffer.from(encryptedData.iv, 'base64');
|
|
27
|
+
const authTag = Buffer.from(encryptedData.authTag, 'base64');
|
|
28
|
+
// Create decipher
|
|
29
|
+
const decipher = createDecipheriv(this.ALGORITHM, key, iv);
|
|
30
|
+
decipher.setAuthTag(authTag);
|
|
31
|
+
// Decrypt data
|
|
32
|
+
let decrypted = decipher.update(encryptedData.encryptedContent, 'base64', 'utf8');
|
|
33
|
+
decrypted += decipher.final('utf8');
|
|
34
|
+
// Parse JSON
|
|
35
|
+
const storage = JSON.parse(decrypted);
|
|
36
|
+
return storage;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
throw new BrokerAuthError('Failed to decrypt broker storage. The password may be incorrect or the file may be corrupted.', BrokerAuthErrorCode.DECRYPTION_FAILED, error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Derive encryption key from password using PBKDF2
|
|
44
|
+
* @param password - User password
|
|
45
|
+
* @param salt - Salt for key derivation
|
|
46
|
+
* @returns Derived encryption key
|
|
47
|
+
*/
|
|
48
|
+
static async deriveKey(password, salt) {
|
|
49
|
+
try {
|
|
50
|
+
if (!password || password.length === 0) {
|
|
51
|
+
throw new BrokerAuthError('Password cannot be empty', BrokerAuthErrorCode.INVALID_PASSWORD);
|
|
52
|
+
}
|
|
53
|
+
return await pbkdf2Async(password, salt, this.ITERATIONS, this.KEY_LENGTH, this.DIGEST);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof BrokerAuthError) {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
throw new BrokerAuthError('Failed to derive encryption key', BrokerAuthErrorCode.ENCRYPTION_FAILED, error);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Encrypt broker storage data
|
|
64
|
+
* @param data - Broker storage to encrypt
|
|
65
|
+
* @param key - Encryption key
|
|
66
|
+
* @returns Encrypted data with metadata
|
|
67
|
+
*/
|
|
68
|
+
static async encrypt(data, key) {
|
|
69
|
+
try {
|
|
70
|
+
// Generate random IV
|
|
71
|
+
const iv = randomBytes(this.IV_LENGTH);
|
|
72
|
+
// Create cipher
|
|
73
|
+
const cipher = createCipheriv(this.ALGORITHM, key, iv);
|
|
74
|
+
// Encrypt data
|
|
75
|
+
const plaintext = JSON.stringify(data);
|
|
76
|
+
let encrypted = cipher.update(plaintext, 'utf8', 'base64');
|
|
77
|
+
encrypted += cipher.final('base64');
|
|
78
|
+
// Get authentication tag
|
|
79
|
+
const authTag = cipher.getAuthTag();
|
|
80
|
+
// Generate new salt for next key derivation
|
|
81
|
+
const salt = this.generateSalt();
|
|
82
|
+
return {
|
|
83
|
+
authTag: authTag.toString('base64'),
|
|
84
|
+
encryptedContent: encrypted,
|
|
85
|
+
iv: iv.toString('base64'),
|
|
86
|
+
metadata: {
|
|
87
|
+
algorithm: this.ALGORITHM,
|
|
88
|
+
iterations: this.ITERATIONS,
|
|
89
|
+
keyDerivation: 'pbkdf2',
|
|
90
|
+
saltLength: this.SALT_LENGTH,
|
|
91
|
+
},
|
|
92
|
+
salt: salt.toString('base64'),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
throw new BrokerAuthError('Failed to encrypt broker storage', BrokerAuthErrorCode.ENCRYPTION_FAILED, error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Generate cryptographically secure random salt
|
|
101
|
+
* @returns Random salt buffer
|
|
102
|
+
*/
|
|
103
|
+
static generateSalt() {
|
|
104
|
+
return randomBytes(this.SALT_LENGTH);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ScConnection } from '../util/sc-connection.js';
|
|
2
|
+
import { type BrokerAuth } from './auth-types.js';
|
|
3
|
+
import { KeychainService } from './keychain.js';
|
|
4
|
+
/**
|
|
5
|
+
* Manager for broker authentication storage
|
|
6
|
+
* Handles encrypted storage of broker credentials
|
|
7
|
+
*/
|
|
8
|
+
export declare class BrokerAuthManager {
|
|
9
|
+
private static instance;
|
|
10
|
+
private readonly configDir;
|
|
11
|
+
private readonly configFile;
|
|
12
|
+
private encryptionKey;
|
|
13
|
+
private readonly keychainService;
|
|
14
|
+
private machineId;
|
|
15
|
+
private masterKey;
|
|
16
|
+
private storage;
|
|
17
|
+
private constructor();
|
|
18
|
+
/**
|
|
19
|
+
* Get singleton instance
|
|
20
|
+
* @param keychainService - Optional keychain service for testing
|
|
21
|
+
*/
|
|
22
|
+
static getInstance(keychainService?: KeychainService): BrokerAuthManager;
|
|
23
|
+
/**
|
|
24
|
+
* Add a new broker configuration
|
|
25
|
+
* @param broker - Broker authentication configuration
|
|
26
|
+
*/
|
|
27
|
+
addBroker(broker: BrokerAuth): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Check if broker exists
|
|
30
|
+
* @param name - Broker name
|
|
31
|
+
* @returns true if broker exists
|
|
32
|
+
*/
|
|
33
|
+
brokerExists(name: string): Promise<boolean>;
|
|
34
|
+
/**
|
|
35
|
+
* Clear all broker configurations
|
|
36
|
+
*/
|
|
37
|
+
clearAll(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Create ScConnection instance from stored broker config
|
|
40
|
+
* @param brokerName - Name of the broker to connect to
|
|
41
|
+
* @param timeout - Optional timeout override
|
|
42
|
+
* @returns Configured ScConnection instance
|
|
43
|
+
*/
|
|
44
|
+
createConnection(brokerName: string, timeout?: number): Promise<ScConnection>;
|
|
45
|
+
/**
|
|
46
|
+
* Get all broker configurations
|
|
47
|
+
* @returns Array of all broker configurations
|
|
48
|
+
*/
|
|
49
|
+
getAllBrokers(): Promise<BrokerAuth[]>;
|
|
50
|
+
/**
|
|
51
|
+
* Get broker configuration by name
|
|
52
|
+
* @param name - Broker name/alias
|
|
53
|
+
* @returns Broker configuration or null if not found
|
|
54
|
+
*/
|
|
55
|
+
getBroker(name: string): Promise<BrokerAuth | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Initialize the auth manager with encryption key derived from OS keychain and machine ID
|
|
58
|
+
*/
|
|
59
|
+
initialize(): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* List all broker names
|
|
62
|
+
* @returns Array of broker names
|
|
63
|
+
*/
|
|
64
|
+
listBrokers(): Promise<string[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Remove broker configuration
|
|
67
|
+
* @param name - Broker name to remove
|
|
68
|
+
*/
|
|
69
|
+
removeBroker(name: string): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Update existing broker configuration
|
|
72
|
+
* @param name - Broker name to update
|
|
73
|
+
* @param updates - Partial updates to apply
|
|
74
|
+
*/
|
|
75
|
+
updateBroker(name: string, updates: Partial<Omit<BrokerAuth, 'name'>>): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Ensure manager is initialized
|
|
78
|
+
*/
|
|
79
|
+
private ensureInitialized;
|
|
80
|
+
/**
|
|
81
|
+
* Check if config file exists
|
|
82
|
+
*/
|
|
83
|
+
private fileExists;
|
|
84
|
+
/**
|
|
85
|
+
* Load storage from encrypted file
|
|
86
|
+
* @param combinedKey - Combined master key and machine ID for decryption
|
|
87
|
+
*/
|
|
88
|
+
private loadStorage;
|
|
89
|
+
/**
|
|
90
|
+
* Save storage to encrypted file
|
|
91
|
+
*/
|
|
92
|
+
private saveStorage;
|
|
93
|
+
/**
|
|
94
|
+
* Validate broker configuration
|
|
95
|
+
* @param broker - Broker to validate
|
|
96
|
+
*/
|
|
97
|
+
private validateBroker;
|
|
98
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { ScConnection } from '../util/sc-connection.js';
|
|
5
|
+
import { BrokerAuthEncryption } from './auth-encryption.js';
|
|
6
|
+
import { AuthType, BrokerAuthError, BrokerAuthErrorCode, } from './auth-types.js';
|
|
7
|
+
import { KeychainService } from './keychain.js';
|
|
8
|
+
const SERVICE_NAME = 'local';
|
|
9
|
+
const KEY_NAME = 'sc-cli';
|
|
10
|
+
/**
|
|
11
|
+
* Manager for broker authentication storage
|
|
12
|
+
* Handles encrypted storage of broker credentials
|
|
13
|
+
*/
|
|
14
|
+
export class BrokerAuthManager {
|
|
15
|
+
static instance = null;
|
|
16
|
+
configDir;
|
|
17
|
+
configFile;
|
|
18
|
+
encryptionKey = null;
|
|
19
|
+
keychainService;
|
|
20
|
+
machineId = null;
|
|
21
|
+
masterKey = null;
|
|
22
|
+
storage = null;
|
|
23
|
+
constructor(keychainService) {
|
|
24
|
+
const homeDirectory = homedir();
|
|
25
|
+
this.configDir = join(homeDirectory, '.sc');
|
|
26
|
+
this.configFile = join(this.configDir, 'brokers.json');
|
|
27
|
+
this.keychainService = keychainService ?? new KeychainService();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get singleton instance
|
|
31
|
+
* @param keychainService - Optional keychain service for testing
|
|
32
|
+
*/
|
|
33
|
+
static getInstance(keychainService) {
|
|
34
|
+
if (!BrokerAuthManager.instance) {
|
|
35
|
+
BrokerAuthManager.instance = new BrokerAuthManager(keychainService);
|
|
36
|
+
}
|
|
37
|
+
return BrokerAuthManager.instance;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Add a new broker configuration
|
|
41
|
+
* @param broker - Broker authentication configuration
|
|
42
|
+
*/
|
|
43
|
+
async addBroker(broker) {
|
|
44
|
+
this.ensureInitialized();
|
|
45
|
+
// Validate broker
|
|
46
|
+
this.validateBroker(broker);
|
|
47
|
+
// Check if broker already exists
|
|
48
|
+
const existing = this.storage.brokers.find((b) => b.name === broker.name);
|
|
49
|
+
if (existing) {
|
|
50
|
+
throw new BrokerAuthError(`Broker '${broker.name}' already exists`, BrokerAuthErrorCode.BROKER_ALREADY_EXISTS);
|
|
51
|
+
}
|
|
52
|
+
// Add broker
|
|
53
|
+
this.storage.brokers.push(broker);
|
|
54
|
+
// Save to file
|
|
55
|
+
await this.saveStorage();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if broker exists
|
|
59
|
+
* @param name - Broker name
|
|
60
|
+
* @returns true if broker exists
|
|
61
|
+
*/
|
|
62
|
+
async brokerExists(name) {
|
|
63
|
+
this.ensureInitialized();
|
|
64
|
+
return this.storage.brokers.some((b) => b.name === name);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Clear all broker configurations
|
|
68
|
+
*/
|
|
69
|
+
async clearAll() {
|
|
70
|
+
this.ensureInitialized();
|
|
71
|
+
this.storage.brokers = [];
|
|
72
|
+
await this.saveStorage();
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create ScConnection instance from stored broker config
|
|
76
|
+
* @param brokerName - Name of the broker to connect to
|
|
77
|
+
* @param timeout - Optional timeout override
|
|
78
|
+
* @returns Configured ScConnection instance
|
|
79
|
+
*/
|
|
80
|
+
async createConnection(brokerName, timeout = 10_000) {
|
|
81
|
+
this.ensureInitialized();
|
|
82
|
+
const broker = await this.getBroker(brokerName);
|
|
83
|
+
if (!broker) {
|
|
84
|
+
throw new BrokerAuthError(`Broker '${brokerName}' not found`, BrokerAuthErrorCode.BROKER_NOT_FOUND);
|
|
85
|
+
}
|
|
86
|
+
const baseURL = `${broker.sempEndpoint}:${broker.sempPort}`;
|
|
87
|
+
const accessToken = broker.authType === AuthType.OAUTH ? broker.accessToken : broker.encodedCredentials;
|
|
88
|
+
const isBasic = broker.authType === AuthType.BASIC;
|
|
89
|
+
return new ScConnection(baseURL, accessToken, timeout, isBasic);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get all broker configurations
|
|
93
|
+
* @returns Array of all broker configurations
|
|
94
|
+
*/
|
|
95
|
+
async getAllBrokers() {
|
|
96
|
+
this.ensureInitialized();
|
|
97
|
+
return [...this.storage.brokers];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get broker configuration by name
|
|
101
|
+
* @param name - Broker name/alias
|
|
102
|
+
* @returns Broker configuration or null if not found
|
|
103
|
+
*/
|
|
104
|
+
async getBroker(name) {
|
|
105
|
+
this.ensureInitialized();
|
|
106
|
+
const broker = this.storage.brokers.find((b) => b.name === name);
|
|
107
|
+
return broker ?? null;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Initialize the auth manager with encryption key derived from OS keychain and machine ID
|
|
111
|
+
*/
|
|
112
|
+
async initialize() {
|
|
113
|
+
try {
|
|
114
|
+
// Get machine ID
|
|
115
|
+
this.machineId = this.keychainService.getMachineId();
|
|
116
|
+
// Get or create master key from OS keychain
|
|
117
|
+
this.masterKey = await this.keychainService.getPassword(KEY_NAME, SERVICE_NAME);
|
|
118
|
+
if (!this.masterKey) {
|
|
119
|
+
// Generate new master key and store in OS keychain
|
|
120
|
+
this.masterKey = this.keychainService.generateMasterKey();
|
|
121
|
+
await this.keychainService.setPassword(KEY_NAME, SERVICE_NAME, this.masterKey);
|
|
122
|
+
}
|
|
123
|
+
// Combine master key with machine ID for encryption
|
|
124
|
+
const combinedKey = `${this.masterKey}:${this.machineId}`;
|
|
125
|
+
// Try to load existing storage
|
|
126
|
+
const fileExists = await this.fileExists();
|
|
127
|
+
if (fileExists) {
|
|
128
|
+
// Load existing file and derive key from stored salt
|
|
129
|
+
await this.loadStorage(combinedKey);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Create new storage with new salt
|
|
133
|
+
const salt = BrokerAuthEncryption.generateSalt();
|
|
134
|
+
this.encryptionKey = await BrokerAuthEncryption.deriveKey(combinedKey, salt);
|
|
135
|
+
this.storage = {
|
|
136
|
+
brokers: [],
|
|
137
|
+
version: '1.0.0',
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (error instanceof BrokerAuthError) {
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
throw new BrokerAuthError('Failed to initialize broker auth manager', BrokerAuthErrorCode.NOT_INITIALIZED, error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* List all broker names
|
|
150
|
+
* @returns Array of broker names
|
|
151
|
+
*/
|
|
152
|
+
async listBrokers() {
|
|
153
|
+
this.ensureInitialized();
|
|
154
|
+
return this.storage.brokers.map((b) => b.name);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Remove broker configuration
|
|
158
|
+
* @param name - Broker name to remove
|
|
159
|
+
*/
|
|
160
|
+
async removeBroker(name) {
|
|
161
|
+
this.ensureInitialized();
|
|
162
|
+
const index = this.storage.brokers.findIndex((b) => b.name === name);
|
|
163
|
+
if (index === -1) {
|
|
164
|
+
throw new BrokerAuthError(`Broker '${name}' not found`, BrokerAuthErrorCode.BROKER_NOT_FOUND);
|
|
165
|
+
}
|
|
166
|
+
// Remove broker
|
|
167
|
+
this.storage.brokers.splice(index, 1);
|
|
168
|
+
// Save to file
|
|
169
|
+
await this.saveStorage();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Update existing broker configuration
|
|
173
|
+
* @param name - Broker name to update
|
|
174
|
+
* @param updates - Partial updates to apply
|
|
175
|
+
*/
|
|
176
|
+
async updateBroker(name, updates) {
|
|
177
|
+
this.ensureInitialized();
|
|
178
|
+
const index = this.storage.brokers.findIndex((b) => b.name === name);
|
|
179
|
+
if (index === -1) {
|
|
180
|
+
throw new BrokerAuthError(`Broker '${name}' not found`, BrokerAuthErrorCode.BROKER_NOT_FOUND);
|
|
181
|
+
}
|
|
182
|
+
// Merge updates
|
|
183
|
+
const updated = {
|
|
184
|
+
...this.storage.brokers[index],
|
|
185
|
+
...updates,
|
|
186
|
+
name, // Ensure name doesn't change
|
|
187
|
+
};
|
|
188
|
+
// Validate updated broker
|
|
189
|
+
this.validateBroker(updated);
|
|
190
|
+
// Update broker
|
|
191
|
+
this.storage.brokers[index] = updated;
|
|
192
|
+
// Save to file
|
|
193
|
+
await this.saveStorage();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Ensure manager is initialized
|
|
197
|
+
*/
|
|
198
|
+
ensureInitialized() {
|
|
199
|
+
if (!this.encryptionKey || !this.storage) {
|
|
200
|
+
throw new BrokerAuthError('BrokerAuthManager not initialized. Call initialize() first.', BrokerAuthErrorCode.NOT_INITIALIZED);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Check if config file exists
|
|
205
|
+
*/
|
|
206
|
+
async fileExists() {
|
|
207
|
+
try {
|
|
208
|
+
await readFile(this.configFile);
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Load storage from encrypted file
|
|
217
|
+
* @param combinedKey - Combined master key and machine ID for decryption
|
|
218
|
+
*/
|
|
219
|
+
async loadStorage(combinedKey) {
|
|
220
|
+
try {
|
|
221
|
+
const fileContent = await readFile(this.configFile, 'utf8');
|
|
222
|
+
const encryptedData = JSON.parse(fileContent);
|
|
223
|
+
// Derive key from combined key and stored salt
|
|
224
|
+
const salt = Buffer.from(encryptedData.salt, 'base64');
|
|
225
|
+
this.encryptionKey = await BrokerAuthEncryption.deriveKey(combinedKey, salt);
|
|
226
|
+
// Decrypt storage
|
|
227
|
+
this.storage = await BrokerAuthEncryption.decrypt(encryptedData, this.encryptionKey);
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
if (error instanceof BrokerAuthError) {
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
throw new BrokerAuthError('Failed to load broker storage', BrokerAuthErrorCode.FILE_READ_ERROR, error);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Save storage to encrypted file
|
|
238
|
+
*/
|
|
239
|
+
async saveStorage() {
|
|
240
|
+
try {
|
|
241
|
+
if (!this.masterKey || !this.machineId) {
|
|
242
|
+
throw new BrokerAuthError('Auth manager not initialized', BrokerAuthErrorCode.NOT_INITIALIZED);
|
|
243
|
+
}
|
|
244
|
+
// Ensure directory exists
|
|
245
|
+
await mkdir(this.configDir, { mode: 0o700, recursive: true });
|
|
246
|
+
// Encrypt data
|
|
247
|
+
const encrypted = await BrokerAuthEncryption.encrypt(this.storage, this.encryptionKey);
|
|
248
|
+
// Re-derive key with new salt for next save
|
|
249
|
+
const combinedKey = `${this.masterKey}:${this.machineId}`;
|
|
250
|
+
const newSalt = Buffer.from(encrypted.salt, 'base64');
|
|
251
|
+
this.encryptionKey = await BrokerAuthEncryption.deriveKey(combinedKey, newSalt);
|
|
252
|
+
// Write to temp file first (atomic write)
|
|
253
|
+
const jsonData = JSON.stringify(encrypted, null, 2);
|
|
254
|
+
const tempFile = `${this.configFile}.tmp`;
|
|
255
|
+
await writeFile(tempFile, jsonData, { mode: 0o600 });
|
|
256
|
+
// Atomic rename
|
|
257
|
+
await rename(tempFile, this.configFile);
|
|
258
|
+
// Set restrictive permissions (Unix only)
|
|
259
|
+
if (process.platform !== 'win32') {
|
|
260
|
+
// Already set via writeFile mode option
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
// Clean up temp file if it exists
|
|
265
|
+
try {
|
|
266
|
+
await unlink(`${this.configFile}.tmp`);
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
// Ignore cleanup errors
|
|
270
|
+
}
|
|
271
|
+
if (error instanceof BrokerAuthError) {
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
throw new BrokerAuthError('Failed to save broker storage', BrokerAuthErrorCode.FILE_WRITE_ERROR, error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Validate broker configuration
|
|
279
|
+
* @param broker - Broker to validate
|
|
280
|
+
*/
|
|
281
|
+
validateBroker(broker) {
|
|
282
|
+
// Validate name
|
|
283
|
+
if (!broker.name || broker.name.trim() === '') {
|
|
284
|
+
throw new BrokerAuthError('Broker name is required', BrokerAuthErrorCode.INVALID_NAME);
|
|
285
|
+
}
|
|
286
|
+
// Validate endpoint
|
|
287
|
+
if (!broker.sempEndpoint || !(broker.sempEndpoint.startsWith('http://') || broker.sempEndpoint.startsWith('https://'))) {
|
|
288
|
+
throw new BrokerAuthError('SEMP endpoint must start with http:// or https://', BrokerAuthErrorCode.INVALID_ENDPOINT);
|
|
289
|
+
}
|
|
290
|
+
// Validate port
|
|
291
|
+
if (broker.sempPort < 1 || broker.sempPort > 65_535) {
|
|
292
|
+
throw new BrokerAuthError('SEMP port must be between 1 and 65535', BrokerAuthErrorCode.INVALID_PORT);
|
|
293
|
+
}
|
|
294
|
+
// Validate auth-specific fields
|
|
295
|
+
if (broker.authType === AuthType.OAUTH) {
|
|
296
|
+
if (!broker.accessToken || !broker.clientId) {
|
|
297
|
+
throw new BrokerAuthError('OAuth brokers require accessToken and clientId', BrokerAuthErrorCode.INVALID_OAUTH_CONFIG);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else if (broker.authType === AuthType.BASIC) {
|
|
301
|
+
if (!broker.encodedCredentials) {
|
|
302
|
+
throw new BrokerAuthError('Basic auth brokers require encodedCredentials', BrokerAuthErrorCode.INVALID_BASIC_CONFIG);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
throw new BrokerAuthError('Invalid auth type', BrokerAuthErrorCode.INVALID_AUTH_TYPE);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
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
|
+
/**
|
|
45
|
+
* Encryption metadata stored alongside encrypted data
|
|
46
|
+
*/
|
|
47
|
+
export interface EncryptionMetadata {
|
|
48
|
+
algorithm: string;
|
|
49
|
+
iterations: number;
|
|
50
|
+
keyDerivation: string;
|
|
51
|
+
saltLength: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Encrypted data structure
|
|
55
|
+
*/
|
|
56
|
+
export interface EncryptedData {
|
|
57
|
+
authTag: string;
|
|
58
|
+
encryptedContent: string;
|
|
59
|
+
iv: string;
|
|
60
|
+
metadata: EncryptionMetadata;
|
|
61
|
+
salt: string;
|
|
62
|
+
}
|
|
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
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Broker authentication management module
|
|
3
|
+
* Provides encrypted storage for SEMP broker credentials
|
|
4
|
+
*/
|
|
5
|
+
export { BrokerAuthEncryption } from './auth-encryption.js';
|
|
6
|
+
export { BrokerAuthManager } from './auth-manager.js';
|
|
7
|
+
export { AuthType, type BasicBrokerAuth, type BrokerAuth, type BrokerAuthBase, BrokerAuthError, BrokerAuthErrorCode, type BrokerAuthStorage, type EncryptedData, type EncryptionMetadata, type OAuthBrokerAuth, } from './auth-types.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Broker authentication management module
|
|
3
|
+
* Provides encrypted storage for SEMP broker credentials
|
|
4
|
+
*/
|
|
5
|
+
export { BrokerAuthEncryption } from './auth-encryption.js';
|
|
6
|
+
export { BrokerAuthManager } from './auth-manager.js';
|
|
7
|
+
export { AuthType, BrokerAuthError, BrokerAuthErrorCode, } from './auth-types.js';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keychain service for storing and retrieving encryption keys
|
|
3
|
+
* This abstraction allows for easier testing and mocking
|
|
4
|
+
*/
|
|
5
|
+
export declare class KeychainService {
|
|
6
|
+
/**
|
|
7
|
+
* Delete a password from the keychain
|
|
8
|
+
* @param service - Service name
|
|
9
|
+
* @param account - Account name
|
|
10
|
+
* @returns True if deleted, false if not found
|
|
11
|
+
*/
|
|
12
|
+
deletePassword(service: string, account: string): Promise<boolean>;
|
|
13
|
+
/**
|
|
14
|
+
* Generate a random master key
|
|
15
|
+
* @returns Base64-encoded random key
|
|
16
|
+
*/
|
|
17
|
+
generateMasterKey(): string;
|
|
18
|
+
/**
|
|
19
|
+
* Get unique machine identifier
|
|
20
|
+
* @returns Machine ID string
|
|
21
|
+
*/
|
|
22
|
+
getMachineId(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get a password from the keychain
|
|
25
|
+
* @param service - Service name
|
|
26
|
+
* @param account - Account name
|
|
27
|
+
* @returns Password string or null if not found
|
|
28
|
+
*/
|
|
29
|
+
getPassword(service: string, account: string): Promise<null | string>;
|
|
30
|
+
/**
|
|
31
|
+
* Set a password in the keychain
|
|
32
|
+
* @param service - Service name
|
|
33
|
+
* @param account - Account name
|
|
34
|
+
* @param password - Password to store
|
|
35
|
+
*/
|
|
36
|
+
setPassword(service: string, account: string, password: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Lazy load keytar module
|
|
39
|
+
* @returns keytar module
|
|
40
|
+
*/
|
|
41
|
+
private loadKeytar;
|
|
42
|
+
/**
|
|
43
|
+
* Lazy load node-machine-id module
|
|
44
|
+
* @returns node-machine-id module
|
|
45
|
+
*/
|
|
46
|
+
private loadMachineId;
|
|
47
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
/**
|
|
5
|
+
* Keychain service for storing and retrieving encryption keys
|
|
6
|
+
* This abstraction allows for easier testing and mocking
|
|
7
|
+
*/
|
|
8
|
+
export class KeychainService {
|
|
9
|
+
/**
|
|
10
|
+
* Delete a password from the keychain
|
|
11
|
+
* @param service - Service name
|
|
12
|
+
* @param account - Account name
|
|
13
|
+
* @returns True if deleted, false if not found
|
|
14
|
+
*/
|
|
15
|
+
async deletePassword(service, account) {
|
|
16
|
+
const keytar = await this.loadKeytar();
|
|
17
|
+
return keytar.deletePassword(service, account);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generate a random master key
|
|
21
|
+
* @returns Base64-encoded random key
|
|
22
|
+
*/
|
|
23
|
+
generateMasterKey() {
|
|
24
|
+
return randomBytes(32).toString('base64');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get unique machine identifier
|
|
28
|
+
* @returns Machine ID string
|
|
29
|
+
*/
|
|
30
|
+
getMachineId() {
|
|
31
|
+
const machineIdPkg = this.loadMachineId();
|
|
32
|
+
return machineIdPkg.machineIdSync();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get a password from the keychain
|
|
36
|
+
* @param service - Service name
|
|
37
|
+
* @param account - Account name
|
|
38
|
+
* @returns Password string or null if not found
|
|
39
|
+
*/
|
|
40
|
+
async getPassword(service, account) {
|
|
41
|
+
const keytar = await this.loadKeytar();
|
|
42
|
+
return keytar.getPassword(service, account);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Set a password in the keychain
|
|
46
|
+
* @param service - Service name
|
|
47
|
+
* @param account - Account name
|
|
48
|
+
* @param password - Password to store
|
|
49
|
+
*/
|
|
50
|
+
async setPassword(service, account, password) {
|
|
51
|
+
const keytar = await this.loadKeytar();
|
|
52
|
+
return keytar.setPassword(service, account, password);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Lazy load keytar module
|
|
56
|
+
* @returns keytar module
|
|
57
|
+
*/
|
|
58
|
+
async loadKeytar() {
|
|
59
|
+
const keytar = await import('keytar');
|
|
60
|
+
return keytar.default;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Lazy load node-machine-id module
|
|
64
|
+
* @returns node-machine-id module
|
|
65
|
+
*/
|
|
66
|
+
loadMachineId() {
|
|
67
|
+
// Use require for CommonJS module (node-machine-id)
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
69
|
+
return require('node-machine-id');
|
|
70
|
+
}
|
|
71
|
+
}
|
package/lib/exported.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { AuthType, type BasicBrokerAuth, type BrokerAuth, BrokerAuthError, BrokerAuthErrorCode, BrokerAuthManager, type OAuthBrokerAuth, } from './auth/index.js';
|
|
1
2
|
export { EnvironmentVariable, envVars } from './config/env-vars.js';
|
|
2
3
|
export { ScCommand } from './sc-command.js';
|
|
3
4
|
export { ScConnection } from './util/sc-connection.js';
|
package/lib/exported.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { AuthType, BrokerAuthError, BrokerAuthErrorCode, BrokerAuthManager, } from './auth/index.js';
|
|
1
2
|
export { EnvironmentVariable, envVars } from './config/env-vars.js';
|
|
2
3
|
export { ScCommand } from './sc-command.js';
|
|
3
4
|
export { ScConnection } from './util/sc-connection.js';
|
|
@@ -2,7 +2,7 @@ import { AxiosRequestConfig } from 'axios';
|
|
|
2
2
|
export declare class ScConnection {
|
|
3
3
|
private axiosInstance;
|
|
4
4
|
private endpointUrl;
|
|
5
|
-
constructor(baseURL?: string, accessToken?: string, timeout?: number,
|
|
5
|
+
constructor(baseURL?: string, accessToken?: string, timeout?: number, basic?: boolean);
|
|
6
6
|
delete<T>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
7
7
|
get<T>(url: string, config?: AxiosRequestConfig): Promise<T>;
|
|
8
8
|
patch<T>(url: string, data?: unknown, config?: AxiosRequestConfig): Promise<T>;
|
|
@@ -3,16 +3,16 @@ import { DefaultBaseUrl, EnvironmentVariable, envVars } from '../config/env-vars
|
|
|
3
3
|
export class ScConnection {
|
|
4
4
|
axiosInstance;
|
|
5
5
|
endpointUrl = '';
|
|
6
|
-
constructor(baseURL = envVars.getString(EnvironmentVariable.SC_BASE_URL, DefaultBaseUrl), accessToken = envVars.getString(EnvironmentVariable.SC_ACCESS_TOKEN, ''), timeout = 10_000,
|
|
6
|
+
constructor(baseURL = envVars.getString(EnvironmentVariable.SC_BASE_URL, DefaultBaseUrl), accessToken = envVars.getString(EnvironmentVariable.SC_ACCESS_TOKEN, ''), timeout = 10_000, basic = false) {
|
|
7
7
|
const apiVersion = envVars.getString(EnvironmentVariable.SC_API_VERSION, 'v2');
|
|
8
8
|
const sempApiVersion = envVars.getString(EnvironmentVariable.SEMP_API_VERSION, 'v2');
|
|
9
|
-
this.endpointUrl =
|
|
9
|
+
this.endpointUrl = basic
|
|
10
10
|
? this.joinPaths(baseURL, `/SEMP/${sempApiVersion}`)
|
|
11
11
|
: this.joinPaths(baseURL, `/api/${apiVersion}`);
|
|
12
12
|
this.axiosInstance = axios.create({
|
|
13
13
|
baseURL: this.endpointUrl,
|
|
14
14
|
headers: {
|
|
15
|
-
Authorization:
|
|
15
|
+
Authorization: basic ? `Basic ${accessToken}` : `Bearer ${accessToken}`,
|
|
16
16
|
'Content-Type': 'application/json',
|
|
17
17
|
},
|
|
18
18
|
timeout,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dishantlangayan/sc-cli-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Base library for the Solace Cloud CLI and plugins",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Dishant Langayan",
|
|
@@ -34,10 +34,12 @@
|
|
|
34
34
|
"@oclif/prettier-config": "^0.2.1",
|
|
35
35
|
"@oclif/test": "^4.1.16",
|
|
36
36
|
"@types/chai": "^5.2.3",
|
|
37
|
+
"@types/chai-as-promised": "^8.0.2",
|
|
37
38
|
"@types/mocha": "^10.0.10",
|
|
38
39
|
"@types/node": "^25.0.3",
|
|
39
40
|
"@types/sinon": "^21.0.0",
|
|
40
41
|
"chai": "^6.2.2",
|
|
42
|
+
"chai-as-promised": "^8.0.2",
|
|
41
43
|
"eslint": "^9",
|
|
42
44
|
"eslint-config-oclif": "^6.0.137",
|
|
43
45
|
"eslint-config-prettier": "^10",
|
|
@@ -52,6 +54,8 @@
|
|
|
52
54
|
"dependencies": {
|
|
53
55
|
"@oclif/core": "^4.8.0",
|
|
54
56
|
"axios": "^1.13.2",
|
|
57
|
+
"keytar": "^7.9.0",
|
|
58
|
+
"node-machine-id": "^1.1.12",
|
|
55
59
|
"table": "^6.9.0"
|
|
56
60
|
}
|
|
57
61
|
}
|