@robinmordasiewicz/f5xc-auth 1.0.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/LICENSE +21 -0
- package/README.md +153 -0
- package/dist/auth/credential-manager.d.ts +177 -0
- package/dist/auth/credential-manager.d.ts.map +1 -0
- package/dist/auth/credential-manager.js +417 -0
- package/dist/auth/credential-manager.js.map +1 -0
- package/dist/auth/http-client.d.ts +86 -0
- package/dist/auth/http-client.d.ts.map +1 -0
- package/dist/auth/http-client.js +255 -0
- package/dist/auth/http-client.js.map +1 -0
- package/dist/auth/index.d.ts +6 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +6 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/paths.d.ts +36 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +68 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/profile/index.d.ts +6 -0
- package/dist/profile/index.d.ts.map +1 -0
- package/dist/profile/index.js +6 -0
- package/dist/profile/index.js.map +1 -0
- package/dist/profile/manager.d.ts +74 -0
- package/dist/profile/manager.d.ts.map +1 -0
- package/dist/profile/manager.js +326 -0
- package/dist/profile/manager.js.map +1 -0
- package/dist/profile/types.d.ts +53 -0
- package/dist/profile/types.d.ts.map +1 -0
- package/dist/profile/types.js +7 -0
- package/dist/profile/types.js.map +1 -0
- package/dist/utils/errors.d.ts +66 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +179 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logging.d.ts +75 -0
- package/dist/utils/logging.d.ts.map +1 -0
- package/dist/utils/logging.js +131 -0
- package/dist/utils/logging.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProfileManager - XDG-compliant profile storage and management
|
|
3
|
+
*
|
|
4
|
+
* Profiles are stored in ~/.config/f5xc/profiles/ (XDG Base Directory compliant)
|
|
5
|
+
*/
|
|
6
|
+
import { promises as fs } from "fs";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import YAML from "yaml";
|
|
9
|
+
import { paths } from "../config/paths.js";
|
|
10
|
+
/**
|
|
11
|
+
* Convert snake_case to camelCase
|
|
12
|
+
*/
|
|
13
|
+
function snakeToCamel(str) {
|
|
14
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Convert object keys from snake_case to camelCase
|
|
18
|
+
*/
|
|
19
|
+
function convertKeysToCamelCase(obj) {
|
|
20
|
+
const result = {};
|
|
21
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
22
|
+
result[snakeToCamel(key)] = value;
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* ProfileManager handles profile CRUD operations with secure file storage
|
|
28
|
+
*/
|
|
29
|
+
export class ProfileManager {
|
|
30
|
+
config;
|
|
31
|
+
constructor() {
|
|
32
|
+
this.config = {
|
|
33
|
+
configDir: paths.configDir,
|
|
34
|
+
profilesDir: paths.profilesDir,
|
|
35
|
+
activeProfileFile: paths.activeProfile,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Ensure config directories exist
|
|
40
|
+
*/
|
|
41
|
+
async ensureDirectories() {
|
|
42
|
+
await fs.mkdir(this.config.profilesDir, {
|
|
43
|
+
recursive: true,
|
|
44
|
+
mode: 0o700,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Get path to profile JSON file
|
|
49
|
+
*/
|
|
50
|
+
getProfilePath(name) {
|
|
51
|
+
return join(this.config.profilesDir, `${name}.json`);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Validate profile name (alphanumeric, dash, underscore only)
|
|
55
|
+
*/
|
|
56
|
+
isValidName(name) {
|
|
57
|
+
return /^[a-zA-Z0-9_-]+$/.test(name) && name.length > 0 && name.length <= 64;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validate API URL format
|
|
61
|
+
*/
|
|
62
|
+
isValidUrl(url) {
|
|
63
|
+
try {
|
|
64
|
+
const parsed = new URL(url);
|
|
65
|
+
return parsed.protocol === "https:" || parsed.protocol === "http:";
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* List all saved profiles
|
|
73
|
+
*/
|
|
74
|
+
async list() {
|
|
75
|
+
await this.ensureDirectories();
|
|
76
|
+
try {
|
|
77
|
+
const files = await fs.readdir(this.config.profilesDir);
|
|
78
|
+
const profileNames = new Set();
|
|
79
|
+
// Collect unique profile names from filenames
|
|
80
|
+
for (const file of files) {
|
|
81
|
+
// Support both .json and .yaml/.yml extensions
|
|
82
|
+
let name = null;
|
|
83
|
+
if (file.endsWith(".json")) {
|
|
84
|
+
name = file.slice(0, -5);
|
|
85
|
+
}
|
|
86
|
+
else if (file.endsWith(".yaml")) {
|
|
87
|
+
name = file.slice(0, -5);
|
|
88
|
+
}
|
|
89
|
+
else if (file.endsWith(".yml")) {
|
|
90
|
+
name = file.slice(0, -4);
|
|
91
|
+
}
|
|
92
|
+
if (name) {
|
|
93
|
+
profileNames.add(name);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// Load profiles (get() handles file extension priority)
|
|
97
|
+
const profiles = [];
|
|
98
|
+
for (const name of profileNames) {
|
|
99
|
+
const profile = await this.get(name);
|
|
100
|
+
if (profile) {
|
|
101
|
+
profiles.push(profile);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return profiles.sort((a, b) => a.name.localeCompare(b.name));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get a profile by name
|
|
112
|
+
*/
|
|
113
|
+
async get(name) {
|
|
114
|
+
await this.ensureDirectories();
|
|
115
|
+
// Try different file extensions in order of preference
|
|
116
|
+
const extensions = [".json", ".yaml", ".yml"];
|
|
117
|
+
for (const ext of extensions) {
|
|
118
|
+
const path = join(this.config.profilesDir, `${name}${ext}`);
|
|
119
|
+
try {
|
|
120
|
+
const data = await fs.readFile(path, "utf-8");
|
|
121
|
+
let parsed;
|
|
122
|
+
if (ext === ".json") {
|
|
123
|
+
parsed = JSON.parse(data);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// Parse YAML and convert snake_case to camelCase
|
|
127
|
+
parsed = YAML.parse(data);
|
|
128
|
+
parsed = convertKeysToCamelCase(parsed);
|
|
129
|
+
}
|
|
130
|
+
return parsed;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Try next extension
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Save a profile (create or update)
|
|
141
|
+
*/
|
|
142
|
+
async save(profile) {
|
|
143
|
+
await this.ensureDirectories();
|
|
144
|
+
if (!this.isValidName(profile.name)) {
|
|
145
|
+
return {
|
|
146
|
+
success: false,
|
|
147
|
+
message: "Invalid profile name. Use alphanumeric characters, dashes, and underscores only (max 64 chars).",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (!this.isValidUrl(profile.apiUrl)) {
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
message: "Invalid API URL. Must be a valid HTTP/HTTPS URL.",
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// Require at least one form of authentication
|
|
157
|
+
if (!profile.apiToken && !profile.cert && !profile.p12Bundle) {
|
|
158
|
+
return {
|
|
159
|
+
success: false,
|
|
160
|
+
message: "Profile must have at least one authentication method (token, certificate, or P12 bundle).",
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const path = this.getProfilePath(profile.name);
|
|
165
|
+
const data = JSON.stringify(profile, null, 2);
|
|
166
|
+
// Write with secure permissions (owner read/write only)
|
|
167
|
+
await fs.writeFile(path, data, { mode: 0o600 });
|
|
168
|
+
return {
|
|
169
|
+
success: true,
|
|
170
|
+
message: `Profile '${profile.name}' saved successfully.`,
|
|
171
|
+
profile,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
return {
|
|
176
|
+
success: false,
|
|
177
|
+
message: `Failed to save profile: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Delete a profile by name
|
|
183
|
+
*/
|
|
184
|
+
async delete(name) {
|
|
185
|
+
await this.ensureDirectories();
|
|
186
|
+
// Check if profile exists
|
|
187
|
+
const existing = await this.get(name);
|
|
188
|
+
if (!existing) {
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
message: `Profile '${name}' not found.`,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
// Check if it's the active profile
|
|
195
|
+
const active = await this.getActive();
|
|
196
|
+
if (active === name) {
|
|
197
|
+
return {
|
|
198
|
+
success: false,
|
|
199
|
+
message: `Cannot delete active profile '${name}'. Switch to another profile first.`,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
const path = this.getProfilePath(name);
|
|
204
|
+
await fs.unlink(path);
|
|
205
|
+
return {
|
|
206
|
+
success: true,
|
|
207
|
+
message: `Profile '${name}' deleted successfully.`,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
return {
|
|
212
|
+
success: false,
|
|
213
|
+
message: `Failed to delete profile: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Get the name of the active profile
|
|
219
|
+
*/
|
|
220
|
+
async getActive() {
|
|
221
|
+
try {
|
|
222
|
+
const name = await fs.readFile(this.config.activeProfileFile, "utf-8");
|
|
223
|
+
return name.trim() || null;
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Clear the active profile (used for force delete)
|
|
231
|
+
*/
|
|
232
|
+
async clearActive() {
|
|
233
|
+
try {
|
|
234
|
+
await fs.unlink(this.config.activeProfileFile);
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Ignore if file doesn't exist
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Set the active profile
|
|
242
|
+
*/
|
|
243
|
+
async setActive(name) {
|
|
244
|
+
await this.ensureDirectories();
|
|
245
|
+
// Verify profile exists
|
|
246
|
+
const profile = await this.get(name);
|
|
247
|
+
if (!profile) {
|
|
248
|
+
return {
|
|
249
|
+
success: false,
|
|
250
|
+
message: `Profile '${name}' not found.`,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
await fs.writeFile(this.config.activeProfileFile, name, {
|
|
255
|
+
mode: 0o600,
|
|
256
|
+
});
|
|
257
|
+
return {
|
|
258
|
+
success: true,
|
|
259
|
+
message: `Switched to profile '${name}'.`,
|
|
260
|
+
profile,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
return {
|
|
265
|
+
success: false,
|
|
266
|
+
message: `Failed to set active profile: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Get the active profile (full profile data)
|
|
272
|
+
*/
|
|
273
|
+
async getActiveProfile() {
|
|
274
|
+
const name = await this.getActive();
|
|
275
|
+
if (!name) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
return this.get(name);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Check if a profile exists
|
|
282
|
+
*/
|
|
283
|
+
async exists(name) {
|
|
284
|
+
const profile = await this.get(name);
|
|
285
|
+
return profile !== null;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Mask sensitive fields for display
|
|
289
|
+
*/
|
|
290
|
+
maskProfile(profile) {
|
|
291
|
+
const masked = {
|
|
292
|
+
name: profile.name,
|
|
293
|
+
apiUrl: profile.apiUrl,
|
|
294
|
+
};
|
|
295
|
+
if (profile.apiToken) {
|
|
296
|
+
// Show only last 4 characters
|
|
297
|
+
const len = profile.apiToken.length;
|
|
298
|
+
masked.apiToken = len > 4 ? `****${profile.apiToken.slice(-4)}` : "****";
|
|
299
|
+
}
|
|
300
|
+
if (profile.p12Bundle) {
|
|
301
|
+
masked.p12Bundle = "[configured]";
|
|
302
|
+
}
|
|
303
|
+
if (profile.cert) {
|
|
304
|
+
masked.cert = "[configured]";
|
|
305
|
+
}
|
|
306
|
+
if (profile.key) {
|
|
307
|
+
masked.key = "[configured]";
|
|
308
|
+
}
|
|
309
|
+
if (profile.defaultNamespace) {
|
|
310
|
+
masked.defaultNamespace = profile.defaultNamespace;
|
|
311
|
+
}
|
|
312
|
+
return masked;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Singleton instance
|
|
316
|
+
let managerInstance = null;
|
|
317
|
+
/**
|
|
318
|
+
* Get the global ProfileManager instance
|
|
319
|
+
*/
|
|
320
|
+
export function getProfileManager() {
|
|
321
|
+
if (!managerInstance) {
|
|
322
|
+
managerInstance = new ProfileManager();
|
|
323
|
+
}
|
|
324
|
+
return managerInstance;
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/profile/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile types for F5 XC authentication and configuration
|
|
3
|
+
*
|
|
4
|
+
* Profiles are stored in ~/.config/f5xc/profiles/ (XDG Base Directory compliant)
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Profile represents a saved API connection configuration
|
|
8
|
+
*/
|
|
9
|
+
export interface Profile {
|
|
10
|
+
/** Unique profile name */
|
|
11
|
+
name: string;
|
|
12
|
+
/** F5 XC API URL (e.g., https://tenant.console.ves.volterra.io) */
|
|
13
|
+
apiUrl: string;
|
|
14
|
+
/** API token for authentication */
|
|
15
|
+
apiToken?: string;
|
|
16
|
+
/** P12 bundle for certificate authentication */
|
|
17
|
+
p12Bundle?: string;
|
|
18
|
+
/** Certificate for mTLS authentication */
|
|
19
|
+
cert?: string;
|
|
20
|
+
/** Private key for mTLS authentication */
|
|
21
|
+
key?: string;
|
|
22
|
+
/** Default namespace for API operations */
|
|
23
|
+
defaultNamespace?: string;
|
|
24
|
+
/** Disable TLS certificate verification (staging/development only) */
|
|
25
|
+
tlsInsecure?: boolean;
|
|
26
|
+
/** Path to custom CA bundle for TLS verification */
|
|
27
|
+
caBundle?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Profile storage configuration
|
|
31
|
+
*/
|
|
32
|
+
export interface ProfileConfig {
|
|
33
|
+
/** Base directory for profile storage */
|
|
34
|
+
configDir: string;
|
|
35
|
+
/** Directory containing profile JSON files */
|
|
36
|
+
profilesDir: string;
|
|
37
|
+
/** File tracking active profile name */
|
|
38
|
+
activeProfileFile: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Result of profile operations
|
|
42
|
+
*/
|
|
43
|
+
export interface ProfileResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
message: string;
|
|
46
|
+
profile?: Profile;
|
|
47
|
+
profiles?: Profile[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Profile validation errors
|
|
51
|
+
*/
|
|
52
|
+
export type ProfileValidationError = "INVALID_NAME" | "INVALID_URL" | "MISSING_AUTH" | "PROFILE_EXISTS" | "PROFILE_NOT_FOUND" | "CANNOT_DELETE_ACTIVE";
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/profile/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,aAAa,GACb,cAAc,GACd,gBAAgB,GAChB,mBAAmB,GACnB,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/profile/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for f5xc-auth
|
|
3
|
+
*
|
|
4
|
+
* Provides typed error classes for different error scenarios.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Base error class for F5XC errors
|
|
8
|
+
*/
|
|
9
|
+
export declare class F5XCError extends Error {
|
|
10
|
+
/** Error code for categorization */
|
|
11
|
+
readonly code: string;
|
|
12
|
+
/** Additional error context */
|
|
13
|
+
readonly context?: Record<string, unknown>;
|
|
14
|
+
constructor(message: string, code: string, context?: Record<string, unknown>);
|
|
15
|
+
/**
|
|
16
|
+
* Convert error to JSON representation
|
|
17
|
+
*/
|
|
18
|
+
toJSON(): Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Authentication-related errors
|
|
22
|
+
*/
|
|
23
|
+
export declare class AuthenticationError extends F5XCError {
|
|
24
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* API request/response errors
|
|
28
|
+
*/
|
|
29
|
+
export declare class F5XCApiError extends F5XCError {
|
|
30
|
+
/** HTTP status code */
|
|
31
|
+
readonly status?: number;
|
|
32
|
+
/** Raw API response */
|
|
33
|
+
readonly response?: unknown;
|
|
34
|
+
constructor(message: string, status?: number, response?: unknown, context?: Record<string, unknown>);
|
|
35
|
+
toJSON(): Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Configuration errors
|
|
39
|
+
*/
|
|
40
|
+
export declare class ConfigurationError extends F5XCError {
|
|
41
|
+
constructor(message: string, context?: Record<string, unknown>);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* SSL/TLS certificate validation errors
|
|
45
|
+
*/
|
|
46
|
+
export declare class SSLCertificateError extends F5XCError {
|
|
47
|
+
/** The hostname that failed validation */
|
|
48
|
+
readonly hostname?: string;
|
|
49
|
+
/** Certificate details if available */
|
|
50
|
+
readonly certInfo?: {
|
|
51
|
+
subject?: string;
|
|
52
|
+
altNames?: string[];
|
|
53
|
+
issuer?: string;
|
|
54
|
+
};
|
|
55
|
+
constructor(message: string, hostname?: string, certInfo?: SSLCertificateError["certInfo"], context?: Record<string, unknown>);
|
|
56
|
+
toJSON(): Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Detect and wrap SSL certificate errors with actionable guidance
|
|
60
|
+
*
|
|
61
|
+
* @param error - Original error to analyze
|
|
62
|
+
* @param apiUrl - Optional API URL for context
|
|
63
|
+
* @returns Wrapped SSLCertificateError with helpful guidance or original error
|
|
64
|
+
*/
|
|
65
|
+
export declare function wrapSSLError(error: unknown, apiUrl?: string): Error;
|
|
66
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAE/B,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAY5E;;OAEG;IACH,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQlC;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;gBACpC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAI/D;AAED;;GAEG;AACH,qBAAa,YAAa,SAAQ,SAAS;IACzC,uBAAuB;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,uBAAuB;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;gBAG1B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,OAAO,EAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAQnC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOlC;AAED;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,SAAS;gBACnC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAI/D;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;IAChD,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;gBAGA,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,EAC1C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAQnC,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOlC;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAkGnE"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error classes for f5xc-auth
|
|
3
|
+
*
|
|
4
|
+
* Provides typed error classes for different error scenarios.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Base error class for F5XC errors
|
|
8
|
+
*/
|
|
9
|
+
export class F5XCError extends Error {
|
|
10
|
+
/** Error code for categorization */
|
|
11
|
+
code;
|
|
12
|
+
/** Additional error context */
|
|
13
|
+
context;
|
|
14
|
+
constructor(message, code, context) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "F5XCError";
|
|
17
|
+
this.code = code;
|
|
18
|
+
this.context = context;
|
|
19
|
+
// Maintains proper stack trace for where our error was thrown
|
|
20
|
+
if (Error.captureStackTrace) {
|
|
21
|
+
Error.captureStackTrace(this, F5XCError);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Convert error to JSON representation
|
|
26
|
+
*/
|
|
27
|
+
toJSON() {
|
|
28
|
+
return {
|
|
29
|
+
name: this.name,
|
|
30
|
+
message: this.message,
|
|
31
|
+
code: this.code,
|
|
32
|
+
context: this.context,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Authentication-related errors
|
|
38
|
+
*/
|
|
39
|
+
export class AuthenticationError extends F5XCError {
|
|
40
|
+
constructor(message, context) {
|
|
41
|
+
super(message, "AUTH_ERROR", context);
|
|
42
|
+
this.name = "AuthenticationError";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* API request/response errors
|
|
47
|
+
*/
|
|
48
|
+
export class F5XCApiError extends F5XCError {
|
|
49
|
+
/** HTTP status code */
|
|
50
|
+
status;
|
|
51
|
+
/** Raw API response */
|
|
52
|
+
response;
|
|
53
|
+
constructor(message, status, response, context) {
|
|
54
|
+
super(message, "API_ERROR", context);
|
|
55
|
+
this.name = "F5XCApiError";
|
|
56
|
+
this.status = status;
|
|
57
|
+
this.response = response;
|
|
58
|
+
}
|
|
59
|
+
toJSON() {
|
|
60
|
+
return {
|
|
61
|
+
...super.toJSON(),
|
|
62
|
+
status: this.status,
|
|
63
|
+
response: this.response,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Configuration errors
|
|
69
|
+
*/
|
|
70
|
+
export class ConfigurationError extends F5XCError {
|
|
71
|
+
constructor(message, context) {
|
|
72
|
+
super(message, "CONFIG_ERROR", context);
|
|
73
|
+
this.name = "ConfigurationError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* SSL/TLS certificate validation errors
|
|
78
|
+
*/
|
|
79
|
+
export class SSLCertificateError extends F5XCError {
|
|
80
|
+
/** The hostname that failed validation */
|
|
81
|
+
hostname;
|
|
82
|
+
/** Certificate details if available */
|
|
83
|
+
certInfo;
|
|
84
|
+
constructor(message, hostname, certInfo, context) {
|
|
85
|
+
super(message, "SSL_CERT_ERROR", context);
|
|
86
|
+
this.name = "SSLCertificateError";
|
|
87
|
+
this.hostname = hostname;
|
|
88
|
+
this.certInfo = certInfo;
|
|
89
|
+
}
|
|
90
|
+
toJSON() {
|
|
91
|
+
return {
|
|
92
|
+
...super.toJSON(),
|
|
93
|
+
hostname: this.hostname,
|
|
94
|
+
certInfo: this.certInfo,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Detect and wrap SSL certificate errors with actionable guidance
|
|
100
|
+
*
|
|
101
|
+
* @param error - Original error to analyze
|
|
102
|
+
* @param apiUrl - Optional API URL for context
|
|
103
|
+
* @returns Wrapped SSLCertificateError with helpful guidance or original error
|
|
104
|
+
*/
|
|
105
|
+
export function wrapSSLError(error, apiUrl) {
|
|
106
|
+
if (!(error instanceof Error)) {
|
|
107
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
108
|
+
}
|
|
109
|
+
const message = error.message.toLowerCase();
|
|
110
|
+
let hostname;
|
|
111
|
+
try {
|
|
112
|
+
if (apiUrl) {
|
|
113
|
+
hostname = new URL(apiUrl).hostname;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Invalid URL, ignore
|
|
118
|
+
}
|
|
119
|
+
// Check for hostname/altname mismatch (the staging certificate issue)
|
|
120
|
+
if (message.includes("altnames") || (message.includes("hostname") && message.includes("match"))) {
|
|
121
|
+
const isStaging = hostname?.includes(".staging.");
|
|
122
|
+
let guidance = `SSL Certificate Error: The server certificate does not cover hostname "${hostname ?? "unknown"}".`;
|
|
123
|
+
if (isStaging) {
|
|
124
|
+
guidance += `
|
|
125
|
+
|
|
126
|
+
This is a known issue with F5 XC staging environments. The wildcard certificate
|
|
127
|
+
*.console.ves.volterra.io does not match multi-level subdomains like
|
|
128
|
+
tenant.staging.console.ves.volterra.io.
|
|
129
|
+
|
|
130
|
+
SOLUTIONS:
|
|
131
|
+
1. (Recommended) Set F5XC_CA_BUNDLE=/path/to/custom-ca.crt
|
|
132
|
+
2. (Development only) Set F5XC_TLS_INSECURE=true to bypass verification
|
|
133
|
+
WARNING: Never use insecure mode in production!
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
export F5XC_TLS_INSECURE=true`;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
guidance += `
|
|
140
|
+
|
|
141
|
+
SOLUTIONS:
|
|
142
|
+
1. Verify the API URL is correct: ${apiUrl ?? "not set"}
|
|
143
|
+
2. If using a custom CA, set F5XC_CA_BUNDLE=/path/to/ca-bundle.crt
|
|
144
|
+
3. Check if the certificate has expired or is self-signed`;
|
|
145
|
+
}
|
|
146
|
+
return new SSLCertificateError(guidance, hostname, undefined, {
|
|
147
|
+
originalError: error.message,
|
|
148
|
+
apiUrl,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
// Check for self-signed certificates
|
|
152
|
+
if (message.includes("self signed") || message.includes("self-signed")) {
|
|
153
|
+
return new SSLCertificateError(`SSL Certificate Error: Self-signed certificate detected.
|
|
154
|
+
|
|
155
|
+
SOLUTIONS:
|
|
156
|
+
1. (Recommended) Add your CA certificate: F5XC_CA_BUNDLE=/path/to/ca.crt
|
|
157
|
+
2. (Development only) Set F5XC_TLS_INSECURE=true to bypass verification`, hostname, undefined, { originalError: error.message, apiUrl });
|
|
158
|
+
}
|
|
159
|
+
// Check for expired certificates
|
|
160
|
+
if (message.includes("expired") || message.includes("not yet valid")) {
|
|
161
|
+
return new SSLCertificateError(`SSL Certificate Error: Certificate has expired or is not yet valid.
|
|
162
|
+
|
|
163
|
+
Contact your F5 XC administrator to renew the certificate.`, hostname, undefined, { originalError: error.message, apiUrl });
|
|
164
|
+
}
|
|
165
|
+
// Generic SSL error
|
|
166
|
+
if (message.includes("certificate") ||
|
|
167
|
+
message.includes("ssl") ||
|
|
168
|
+
message.includes("tls") ||
|
|
169
|
+
message.includes("unable to verify")) {
|
|
170
|
+
return new SSLCertificateError(`SSL/TLS Error: ${error.message}
|
|
171
|
+
|
|
172
|
+
If this is a staging environment, you may need to:
|
|
173
|
+
1. Set F5XC_CA_BUNDLE=/path/to/ca.crt for custom CA
|
|
174
|
+
2. Set F5XC_TLS_INSECURE=true to disable verification (development only)`, hostname, undefined, { originalError: error.message, apiUrl });
|
|
175
|
+
}
|
|
176
|
+
// Not an SSL error, return original
|
|
177
|
+
return error;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC"}
|