xrootd 1.0.0-beta.2 → 1.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +69 -1
- package/dist/index.mjs +191 -14
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -393,6 +393,47 @@ declare class File {
|
|
|
393
393
|
truncate(size: number): Promise<void>;
|
|
394
394
|
}
|
|
395
395
|
//#endregion
|
|
396
|
+
//#region src/config/sec-env.d.ts
|
|
397
|
+
interface SecEnvOptions {
|
|
398
|
+
/** Environment variable source. Defaults to process.env. */
|
|
399
|
+
env?: Record<string, string | undefined>;
|
|
400
|
+
/** Protocol whitelist (equivalent to XrdSecPROTOCOL). */
|
|
401
|
+
protocolFilter?: string[];
|
|
402
|
+
/** Whether to read GSI variables (X509_*, XrdSecGSI*). Defaults to true. */
|
|
403
|
+
gsi?: boolean;
|
|
404
|
+
/** Whether to read SSS variables (XrdSecSSSKT). Defaults to true. */
|
|
405
|
+
sss?: boolean;
|
|
406
|
+
/** Whether to read KRB5 variables (XrdSecKRB5INITTKN). Defaults to true. */
|
|
407
|
+
krb5?: boolean;
|
|
408
|
+
/** Whether to read PWD variables (XrdSecPWDSRVPUK etc). Defaults to true. */
|
|
409
|
+
pwd?: boolean;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* xrootd security environment variable configuration.
|
|
413
|
+
*
|
|
414
|
+
* Maps C++ xrootd's XrdSec* / X509_* environment variables to a structured
|
|
415
|
+
* config object. Does NOT read process.env directly — the caller provides
|
|
416
|
+
* the env source via constructor options.
|
|
417
|
+
*/
|
|
418
|
+
declare class SecEnv {
|
|
419
|
+
readonly protocolFilter: string[];
|
|
420
|
+
readonly proxyMode: boolean;
|
|
421
|
+
readonly proxyCreds: boolean;
|
|
422
|
+
readonly sssKeytab: string | undefined;
|
|
423
|
+
readonly krb5InitToken: boolean;
|
|
424
|
+
readonly gsiCaDir: string;
|
|
425
|
+
readonly gsiCrlDir: string;
|
|
426
|
+
readonly gsiUserCert: string;
|
|
427
|
+
readonly gsiUserKey: string;
|
|
428
|
+
readonly gsiUserProxy: string;
|
|
429
|
+
readonly pwdServerPubkey: string | undefined;
|
|
430
|
+
readonly username: string | undefined;
|
|
431
|
+
readonly password: string | undefined;
|
|
432
|
+
constructor(options?: SecEnvOptions);
|
|
433
|
+
static fromEnv(env?: Record<string, string | undefined>, options?: Omit<SecEnvOptions, "env">): SecEnv;
|
|
434
|
+
private parseProtocolFilter;
|
|
435
|
+
}
|
|
436
|
+
//#endregion
|
|
396
437
|
//#region src/client.d.ts
|
|
397
438
|
interface XRootDClientOptions {
|
|
398
439
|
credentials?: {
|
|
@@ -401,6 +442,8 @@ interface XRootDClientOptions {
|
|
|
401
442
|
};
|
|
402
443
|
timeout?: number;
|
|
403
444
|
maxRedirects?: number;
|
|
445
|
+
/** Security environment configuration. Enables credential auto-discovery and protocol filtering. */
|
|
446
|
+
secEnv?: SecEnv;
|
|
404
447
|
}
|
|
405
448
|
declare class XRootDClient {
|
|
406
449
|
private readonly url;
|
|
@@ -431,6 +474,31 @@ declare class XRootDClient {
|
|
|
431
474
|
private ensureFileSystem;
|
|
432
475
|
}
|
|
433
476
|
//#endregion
|
|
477
|
+
//#region src/config/loader.d.ts
|
|
478
|
+
interface ResolvedAuthConfig {
|
|
479
|
+
username?: string;
|
|
480
|
+
password?: string;
|
|
481
|
+
sssKey?: Buffer;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Resolve authentication credentials from multiple sources.
|
|
485
|
+
*
|
|
486
|
+
* Priority (high → low):
|
|
487
|
+
* 1. options.credentials (explicit)
|
|
488
|
+
* 2. URL userinfo (root://user:pass@host)
|
|
489
|
+
* 3. SecEnv XrdSecUSER / XrdSecCREDS
|
|
490
|
+
*
|
|
491
|
+
* Also reads the SSS keytab file specified by SecEnv if available.
|
|
492
|
+
*/
|
|
493
|
+
declare function loadAuthConfig(options: {
|
|
494
|
+
url?: XRootDUrl;
|
|
495
|
+
credentials?: {
|
|
496
|
+
username: string;
|
|
497
|
+
password?: string;
|
|
498
|
+
};
|
|
499
|
+
secEnv?: SecEnv;
|
|
500
|
+
}): ResolvedAuthConfig;
|
|
501
|
+
//#endregion
|
|
434
502
|
//#region src/api/filesystem.d.ts
|
|
435
503
|
declare class FileSystem {
|
|
436
504
|
private mux;
|
|
@@ -659,5 +727,5 @@ declare function putBytes(buf: Buffer, offset: number, data: Uint8Array): number
|
|
|
659
727
|
/** Slice `length` bytes from `buf` at `offset`, return `[slice, newOffset]`. */
|
|
660
728
|
declare function getBytes(buf: Buffer, offset: number, length: number): [Buffer, number];
|
|
661
729
|
//#endregion
|
|
662
|
-
export { type AuthConfig, BODY_SIZE, CRED_TYPE, type ChunkInfo, ClientError, DEFAULT_PORT, type DirectoryEntry, type DirectoryList, DirlistOptions, type ErrorResponse, FHANDLE_SIZE, File, FileSystem, type Frame, Framer, HANDSHAKE_FIFTH, HANDSHAKE_FIRST, HANDSHAKE_FOURTH, HANDSHAKE_SECOND, HANDSHAKE_THIRD, type ITransport, type Location, type LocationInfo, type LoginResponse, Message, Multiplexer, OpenFlags, type OpenOptions, type OpenResponse, PROTOCOL_VERSION, type ProtocolInfo, type ProtocolResponse, REQUEST_HDR_SIZE, REQUEST_OFFSET_BODY, REQUEST_OFFSET_DLEN, REQUEST_OFFSET_REQUEST_ID, REQUEST_OFFSET_STREAM_ID, RESPONSE_HDR_SIZE, RESPONSE_OFFSET_BODY, RESPONSE_OFFSET_DLEN, RESPONSE_OFFSET_STATUS, RESPONSE_OFFSET_STREAM_ID, type RedirectResponse, RequestId, ResponseStatus, SESS_ID_SIZE, S_IFDIR, S_IFLNK, ServerError, type Session, StatFlags, type StatInfo, Transport, type WaitResponse, XRootDClient, type XRootDClientOptions, XRootDError, XRootDUrl, buildCloseRequest, buildHandshakeAndProtocol, buildLoginRequest, buildOpenRequest, buildReadRequest, buildStatRequest, buildWriteRequest, createStatInfo, get16, get32, getBytes, getString, handshake, kXR_ExpBind, kXR_ExpLogin, kXR_ableTLS, kXR_bifreqs, kXR_secreqs, kXR_wantTLS, parseErrorResponse, parseLoginResponse, parseOpenResponse, parseProtocolResponse, parseRedirectResponse, parseWaitResponse, put16, put32, putBytes, putString };
|
|
730
|
+
export { type AuthConfig, BODY_SIZE, CRED_TYPE, type ChunkInfo, ClientError, DEFAULT_PORT, type DirectoryEntry, type DirectoryList, DirlistOptions, type ErrorResponse, FHANDLE_SIZE, File, FileSystem, type Frame, Framer, HANDSHAKE_FIFTH, HANDSHAKE_FIRST, HANDSHAKE_FOURTH, HANDSHAKE_SECOND, HANDSHAKE_THIRD, type ITransport, type Location, type LocationInfo, type LoginResponse, Message, Multiplexer, OpenFlags, type OpenOptions, type OpenResponse, PROTOCOL_VERSION, type ProtocolInfo, type ProtocolResponse, REQUEST_HDR_SIZE, REQUEST_OFFSET_BODY, REQUEST_OFFSET_DLEN, REQUEST_OFFSET_REQUEST_ID, REQUEST_OFFSET_STREAM_ID, RESPONSE_HDR_SIZE, RESPONSE_OFFSET_BODY, RESPONSE_OFFSET_DLEN, RESPONSE_OFFSET_STATUS, RESPONSE_OFFSET_STREAM_ID, type RedirectResponse, RequestId, type ResolvedAuthConfig, ResponseStatus, SESS_ID_SIZE, S_IFDIR, S_IFLNK, SecEnv, type SecEnvOptions, ServerError, type Session, StatFlags, type StatInfo, Transport, type WaitResponse, XRootDClient, type XRootDClientOptions, XRootDError, XRootDUrl, buildCloseRequest, buildHandshakeAndProtocol, buildLoginRequest, buildOpenRequest, buildReadRequest, buildStatRequest, buildWriteRequest, createStatInfo, get16, get32, getBytes, getString, handshake, kXR_ExpBind, kXR_ExpLogin, kXR_ableTLS, kXR_bifreqs, kXR_secreqs, kXR_wantTLS, loadAuthConfig, parseErrorResponse, parseLoginResponse, parseOpenResponse, parseProtocolResponse, parseRedirectResponse, parseWaitResponse, put16, put32, putBytes, putString };
|
|
663
731
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import net from "node:net";
|
|
2
2
|
import tls from "node:tls";
|
|
3
|
+
import { createCipheriv } from "node:crypto";
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
3
6
|
//#region src/protocol/constants.ts
|
|
4
7
|
const RequestId = {
|
|
5
8
|
Auth: 3e3,
|
|
@@ -588,8 +591,9 @@ function buildMkdirRequest(streamId, path, mode = 493) {
|
|
|
588
591
|
const msg = new Message(24 + pathBytes.length);
|
|
589
592
|
msg.writeBytes(streamIdToBytes(streamId));
|
|
590
593
|
msg.writeInt16BE(RequestId.Mkdir);
|
|
594
|
+
msg.writeUInt8(0);
|
|
595
|
+
msg.writeBytes(/* @__PURE__ */ new Uint8Array(13));
|
|
591
596
|
msg.writeInt16BE(mode & 65535);
|
|
592
|
-
msg.writeBytes(/* @__PURE__ */ new Uint8Array(14));
|
|
593
597
|
msg.writeInt32BE(pathBytes.length);
|
|
594
598
|
msg.writeBytes(pathBytes);
|
|
595
599
|
return msg.getBuffer();
|
|
@@ -637,13 +641,15 @@ function buildRmRequest(streamId, path) {
|
|
|
637
641
|
function buildMvRequest(streamId, source, target) {
|
|
638
642
|
const srcBytes = strToBytes(source);
|
|
639
643
|
const tgtBytes = strToBytes(target);
|
|
640
|
-
const
|
|
644
|
+
const spaceSep = new Uint8Array([32]);
|
|
645
|
+
const msg = new Message(24 + srcBytes.length + 1 + tgtBytes.length);
|
|
641
646
|
msg.writeBytes(streamIdToBytes(streamId));
|
|
642
647
|
msg.writeInt16BE(RequestId.Mv);
|
|
643
648
|
msg.writeBytes(/* @__PURE__ */ new Uint8Array(14));
|
|
644
649
|
msg.writeInt16BE(srcBytes.length & 65535);
|
|
645
|
-
msg.writeInt32BE(srcBytes.length + tgtBytes.length);
|
|
650
|
+
msg.writeInt32BE(srcBytes.length + 1 + tgtBytes.length);
|
|
646
651
|
msg.writeBytes(srcBytes);
|
|
652
|
+
msg.writeBytes(spaceSep);
|
|
647
653
|
msg.writeBytes(tgtBytes);
|
|
648
654
|
return msg.getBuffer();
|
|
649
655
|
}
|
|
@@ -1189,19 +1195,21 @@ const authProtocols = /* @__PURE__ */ new Map();
|
|
|
1189
1195
|
function registerAuthProtocol(name, factory) {
|
|
1190
1196
|
authProtocols.set(name, factory);
|
|
1191
1197
|
}
|
|
1192
|
-
async function doAuthentication(mux, secReqs, params) {
|
|
1198
|
+
async function doAuthentication(mux, secReqs, params, options) {
|
|
1193
1199
|
if (!secReqs || secReqs.trim().length === 0) return {
|
|
1194
1200
|
prot: "",
|
|
1195
1201
|
uid: 0,
|
|
1196
1202
|
gid: 0
|
|
1197
1203
|
};
|
|
1198
1204
|
const supportedProtocols = secReqs.split(",").map((s) => s.trim());
|
|
1199
|
-
|
|
1205
|
+
const filter = options?.protocolFilter;
|
|
1206
|
+
const candidates = filter?.length ? supportedProtocols.filter((p) => filter.includes(p)) : supportedProtocols;
|
|
1207
|
+
for (const protoName of candidates) {
|
|
1200
1208
|
const factory = authProtocols.get(protoName);
|
|
1201
1209
|
if (!factory) continue;
|
|
1202
1210
|
return await executeAuth(mux, factory(), params);
|
|
1203
1211
|
}
|
|
1204
|
-
throw new XRootDError(ServerError.AuthFailed, `No supported authentication protocol. Server requires: ${secReqs}`);
|
|
1212
|
+
throw new XRootDError(ServerError.AuthFailed, `No supported authentication protocol. Server requires: ${secReqs}` + (filter ? `. Allowed: ${filter.join(",")}` : ""));
|
|
1205
1213
|
}
|
|
1206
1214
|
async function executeAuth(mux, protocol, params) {
|
|
1207
1215
|
const creds = await protocol.getCredentials(params);
|
|
@@ -1254,6 +1262,79 @@ var HostAuth = class {
|
|
|
1254
1262
|
}
|
|
1255
1263
|
};
|
|
1256
1264
|
//#endregion
|
|
1265
|
+
//#region src/utils/crc32.ts
|
|
1266
|
+
function crc32(data) {
|
|
1267
|
+
let crc = 4294967295;
|
|
1268
|
+
for (let i = 0; i < data.length; i++) {
|
|
1269
|
+
crc ^= data[i];
|
|
1270
|
+
for (let j = 0; j < 8; j++) crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
|
|
1271
|
+
}
|
|
1272
|
+
return (crc ^ 4294967295) >>> 0;
|
|
1273
|
+
}
|
|
1274
|
+
//#endregion
|
|
1275
|
+
//#region src/security/sss.ts
|
|
1276
|
+
function pkcs5Pad(data, blockSize) {
|
|
1277
|
+
const padLen = blockSize - data.length % blockSize;
|
|
1278
|
+
const padded = Buffer.alloc(data.length + padLen);
|
|
1279
|
+
data.copy(padded);
|
|
1280
|
+
padded.fill(padLen, data.length);
|
|
1281
|
+
return padded;
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* SSS (Simple Shared Secret) authentication protocol.
|
|
1285
|
+
*
|
|
1286
|
+
* Uses Blowfish-ECB encryption + CRC32 checksum.
|
|
1287
|
+
* Note: Requires Node.js with legacy OpenSSL provider for Blowfish support.
|
|
1288
|
+
* Run with: NODE_OPTIONS=--openssl-legacy-provider
|
|
1289
|
+
*
|
|
1290
|
+
* Or use the static create() method which checks if Blowfish is available.
|
|
1291
|
+
*/
|
|
1292
|
+
var SSSAuth = class {
|
|
1293
|
+
name = "sss";
|
|
1294
|
+
entity = {
|
|
1295
|
+
prot: "sss",
|
|
1296
|
+
uid: 0,
|
|
1297
|
+
gid: 0
|
|
1298
|
+
};
|
|
1299
|
+
complete = false;
|
|
1300
|
+
key;
|
|
1301
|
+
constructor(key) {
|
|
1302
|
+
if (key.length !== 8) throw new Error("SSS key must be 8 bytes");
|
|
1303
|
+
this.key = key;
|
|
1304
|
+
}
|
|
1305
|
+
static isSupported() {
|
|
1306
|
+
try {
|
|
1307
|
+
createCipheriv("bf-ecb", Buffer.alloc(8), null).final();
|
|
1308
|
+
return true;
|
|
1309
|
+
} catch {
|
|
1310
|
+
return false;
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
async getCredentials(params) {
|
|
1314
|
+
const password = params.password || "";
|
|
1315
|
+
const passwordBytes = new TextEncoder().encode(password);
|
|
1316
|
+
const crc = crc32(passwordBytes);
|
|
1317
|
+
const payload = Buffer.alloc(passwordBytes.length + 4);
|
|
1318
|
+
Buffer.from(passwordBytes).copy(payload, 0);
|
|
1319
|
+
payload.writeUInt32BE(crc, passwordBytes.length);
|
|
1320
|
+
const cipher = createCipheriv("bf-ecb", this.key, null);
|
|
1321
|
+
const padded = pkcs5Pad(payload, 8);
|
|
1322
|
+
const encrypted = Buffer.concat([cipher.update(padded), cipher.final()]);
|
|
1323
|
+
this.entity.name = params.username;
|
|
1324
|
+
return new Uint8Array(encrypted);
|
|
1325
|
+
}
|
|
1326
|
+
async processChallenge(_challenge) {
|
|
1327
|
+
this.complete = true;
|
|
1328
|
+
return /* @__PURE__ */ new Uint8Array(0);
|
|
1329
|
+
}
|
|
1330
|
+
isComplete() {
|
|
1331
|
+
return this.complete;
|
|
1332
|
+
}
|
|
1333
|
+
getEntity() {
|
|
1334
|
+
return this.entity;
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
//#endregion
|
|
1257
1338
|
//#region src/api/types.ts
|
|
1258
1339
|
const StatFlags = {
|
|
1259
1340
|
XBitSet: 1,
|
|
@@ -1301,7 +1382,7 @@ function createStatInfo(data) {
|
|
|
1301
1382
|
owner: parts[7] ?? "",
|
|
1302
1383
|
group: parts[8] ?? "",
|
|
1303
1384
|
get isDirectory() {
|
|
1304
|
-
return (
|
|
1385
|
+
return (serverFlags & StatFlags.IsDir) !== 0;
|
|
1305
1386
|
},
|
|
1306
1387
|
get isLink() {
|
|
1307
1388
|
return (mode & S_IFLNK) === S_IFLNK;
|
|
@@ -1383,7 +1464,7 @@ var File = class {
|
|
|
1383
1464
|
const { errnum, errmsg } = parseErrorResponse(frame.body);
|
|
1384
1465
|
throw new XRootDError(errnum, errmsg);
|
|
1385
1466
|
}
|
|
1386
|
-
if (frame.status === ResponseStatus.Ok) return new Uint8Array(frame.body);
|
|
1467
|
+
if (frame.status === ResponseStatus.Ok || frame.status === ResponseStatus.Oksofar) return new Uint8Array(frame.body);
|
|
1387
1468
|
throw new XRootDError(ServerError.ServerError, `Unexpected read response status: ${frame.status}`);
|
|
1388
1469
|
}
|
|
1389
1470
|
async write(offset, data) {
|
|
@@ -1394,7 +1475,7 @@ var File = class {
|
|
|
1394
1475
|
const { errnum, errmsg } = parseErrorResponse(frame.body);
|
|
1395
1476
|
throw new XRootDError(errnum, errmsg);
|
|
1396
1477
|
}
|
|
1397
|
-
if (frame.status === ResponseStatus.Ok) return frame.dlen;
|
|
1478
|
+
if (frame.status === ResponseStatus.Ok) return frame.dlen > 0 ? frame.dlen : data.length;
|
|
1398
1479
|
throw new XRootDError(ServerError.ServerError, `Unexpected write response status: ${frame.status}`);
|
|
1399
1480
|
}
|
|
1400
1481
|
async close() {
|
|
@@ -1492,6 +1573,32 @@ var FileSystem = class {
|
|
|
1492
1573
|
}
|
|
1493
1574
|
};
|
|
1494
1575
|
//#endregion
|
|
1576
|
+
//#region src/config/loader.ts
|
|
1577
|
+
/**
|
|
1578
|
+
* Resolve authentication credentials from multiple sources.
|
|
1579
|
+
*
|
|
1580
|
+
* Priority (high → low):
|
|
1581
|
+
* 1. options.credentials (explicit)
|
|
1582
|
+
* 2. URL userinfo (root://user:pass@host)
|
|
1583
|
+
* 3. SecEnv XrdSecUSER / XrdSecCREDS
|
|
1584
|
+
*
|
|
1585
|
+
* Also reads the SSS keytab file specified by SecEnv if available.
|
|
1586
|
+
*/
|
|
1587
|
+
function loadAuthConfig(options) {
|
|
1588
|
+
const { url, credentials, secEnv } = options;
|
|
1589
|
+
const username = credentials?.username ?? url?.user ?? secEnv?.username;
|
|
1590
|
+
const password = credentials?.password ?? url?.password ?? secEnv?.password;
|
|
1591
|
+
let sssKey;
|
|
1592
|
+
if (secEnv?.sssKeytab) try {
|
|
1593
|
+
sssKey = readFileSync(secEnv.sssKeytab);
|
|
1594
|
+
} catch {}
|
|
1595
|
+
return {
|
|
1596
|
+
username,
|
|
1597
|
+
password,
|
|
1598
|
+
sssKey
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
//#endregion
|
|
1495
1602
|
//#region src/client.ts
|
|
1496
1603
|
var XRootDClient = class {
|
|
1497
1604
|
url;
|
|
@@ -1516,15 +1623,22 @@ var XRootDClient = class {
|
|
|
1516
1623
|
});
|
|
1517
1624
|
if (this.options.timeout) this.mux.setTimeout(this.options.timeout);
|
|
1518
1625
|
this.session = await handshake(this.mux, url, { username: this.options.credentials?.username });
|
|
1626
|
+
const secEnv = this.options.secEnv;
|
|
1627
|
+
const authConfig = loadAuthConfig({
|
|
1628
|
+
url,
|
|
1629
|
+
credentials: this.options.credentials,
|
|
1630
|
+
secEnv
|
|
1631
|
+
});
|
|
1519
1632
|
registerAuthProtocol("host", () => new HostAuth());
|
|
1520
|
-
if (
|
|
1633
|
+
if (authConfig.sssKey && SSSAuth.isSupported()) registerAuthProtocol("sss", () => new SSSAuth(authConfig.sssKey));
|
|
1634
|
+
if (this.session.secReqs && (authConfig.username || authConfig.password)) {
|
|
1521
1635
|
const secEntity = await doAuthentication(this.mux, this.session.secReqs, {
|
|
1522
1636
|
host: url.host,
|
|
1523
1637
|
port: url.port,
|
|
1524
|
-
username:
|
|
1525
|
-
password:
|
|
1638
|
+
username: authConfig.username,
|
|
1639
|
+
password: authConfig.password,
|
|
1526
1640
|
sessid: this.session.sessid
|
|
1527
|
-
});
|
|
1641
|
+
}, { protocolFilter: secEnv?.protocolFilter });
|
|
1528
1642
|
this.session.secEntity = secEntity;
|
|
1529
1643
|
}
|
|
1530
1644
|
this.fs = new FileSystem(this.mux);
|
|
@@ -1611,6 +1725,69 @@ var XRootDClient = class {
|
|
|
1611
1725
|
}
|
|
1612
1726
|
};
|
|
1613
1727
|
//#endregion
|
|
1614
|
-
|
|
1728
|
+
//#region src/config/sec-env.ts
|
|
1729
|
+
/**
|
|
1730
|
+
* xrootd security environment variable configuration.
|
|
1731
|
+
*
|
|
1732
|
+
* Maps C++ xrootd's XrdSec* / X509_* environment variables to a structured
|
|
1733
|
+
* config object. Does NOT read process.env directly — the caller provides
|
|
1734
|
+
* the env source via constructor options.
|
|
1735
|
+
*/
|
|
1736
|
+
var SecEnv = class SecEnv {
|
|
1737
|
+
protocolFilter;
|
|
1738
|
+
proxyMode;
|
|
1739
|
+
proxyCreds;
|
|
1740
|
+
sssKeytab;
|
|
1741
|
+
krb5InitToken;
|
|
1742
|
+
gsiCaDir;
|
|
1743
|
+
gsiCrlDir;
|
|
1744
|
+
gsiUserCert;
|
|
1745
|
+
gsiUserKey;
|
|
1746
|
+
gsiUserProxy;
|
|
1747
|
+
pwdServerPubkey;
|
|
1748
|
+
username;
|
|
1749
|
+
password;
|
|
1750
|
+
constructor(options = {}) {
|
|
1751
|
+
const env = options.env ?? process.env;
|
|
1752
|
+
this.protocolFilter = options.protocolFilter ?? this.parseProtocolFilter(env);
|
|
1753
|
+
this.proxyMode = truthy(env["XrdSecPROXY"]);
|
|
1754
|
+
this.proxyCreds = truthy(env["XrdSecPROXYCREDS"]);
|
|
1755
|
+
this.sssKeytab = options.sss !== false ? env["XrdSecSSSKT"] ?? env["XrdSecsssKT"] : void 0;
|
|
1756
|
+
this.krb5InitToken = options.krb5 !== false ? truthy(env["XrdSecKRB5INITTKN"]) : false;
|
|
1757
|
+
if (options.gsi !== false) {
|
|
1758
|
+
const home = homedir();
|
|
1759
|
+
this.gsiCaDir = env["XrdSecGSICADIR"] ?? env["X509_CERT_DIR"] ?? "/etc/grid-security/certificates";
|
|
1760
|
+
this.gsiCrlDir = env["XrdSecGSICRLDIR"] ?? env["X509_CERT_DIR"] ?? "/etc/grid-security/certificates";
|
|
1761
|
+
this.gsiUserCert = env["XrdSecGSIUSERCERT"] ?? env["X509_USER_CERT"] ?? `${home}/.globus/usercert.pem`;
|
|
1762
|
+
this.gsiUserKey = env["XrdSecGSIUSERKEY"] ?? env["X509_USER_KEY"] ?? `${home}/.globus/userkey.pem`;
|
|
1763
|
+
this.gsiUserProxy = env["XrdSecGSIUSERPROXY"] ?? env["X509_USER_PROXY"] ?? `/tmp/x509up_u${process.getuid?.() ?? 0}`;
|
|
1764
|
+
} else {
|
|
1765
|
+
this.gsiCaDir = "";
|
|
1766
|
+
this.gsiCrlDir = "";
|
|
1767
|
+
this.gsiUserCert = "";
|
|
1768
|
+
this.gsiUserKey = "";
|
|
1769
|
+
this.gsiUserProxy = "";
|
|
1770
|
+
}
|
|
1771
|
+
this.pwdServerPubkey = options.pwd !== false ? env["XrdSecPWDSRVPUK"] : void 0;
|
|
1772
|
+
this.username = env["XrdSecUSER"];
|
|
1773
|
+
this.password = env["XrdSecCREDS"];
|
|
1774
|
+
}
|
|
1775
|
+
static fromEnv(env, options) {
|
|
1776
|
+
return new SecEnv({
|
|
1777
|
+
...options,
|
|
1778
|
+
env: env ?? process.env
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
1781
|
+
parseProtocolFilter(env) {
|
|
1782
|
+
const raw = env["XrdSecPROTOCOL"];
|
|
1783
|
+
if (!raw) return [];
|
|
1784
|
+
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
function truthy(val) {
|
|
1788
|
+
return val !== void 0 && val !== "0" && val !== "";
|
|
1789
|
+
}
|
|
1790
|
+
//#endregion
|
|
1791
|
+
export { BODY_SIZE, CRED_TYPE, ClientError, DEFAULT_PORT, DirlistOptions, FHANDLE_SIZE, File, FileSystem, Framer, HANDSHAKE_FIFTH, HANDSHAKE_FIRST, HANDSHAKE_FOURTH, HANDSHAKE_SECOND, HANDSHAKE_THIRD, Message, Multiplexer, OpenFlags, PROTOCOL_VERSION, REQUEST_HDR_SIZE, REQUEST_OFFSET_BODY, REQUEST_OFFSET_DLEN, REQUEST_OFFSET_REQUEST_ID, REQUEST_OFFSET_STREAM_ID, RESPONSE_HDR_SIZE, RESPONSE_OFFSET_BODY, RESPONSE_OFFSET_DLEN, RESPONSE_OFFSET_STATUS, RESPONSE_OFFSET_STREAM_ID, RequestId, ResponseStatus, SESS_ID_SIZE, S_IFDIR, S_IFLNK, SecEnv, ServerError, StatFlags, Transport, XRootDClient, XRootDError, XRootDUrl, buildCloseRequest, buildHandshakeAndProtocol, buildLoginRequest, buildOpenRequest, buildReadRequest, buildStatRequest, buildWriteRequest, createStatInfo, get16, get32, getBytes, getString, handshake, kXR_ExpBind, kXR_ExpLogin, kXR_ableTLS, kXR_bifreqs, kXR_secreqs, kXR_wantTLS, loadAuthConfig, parseErrorResponse, parseLoginResponse, parseOpenResponse, parseProtocolResponse, parseRedirectResponse, parseWaitResponse, put16, put32, putBytes, putString };
|
|
1615
1792
|
|
|
1616
1793
|
//# sourceMappingURL=index.mjs.map
|