agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
68 lines • 2.56 kB
JavaScript
/**
* directory/port — the four directory operations `directory-password` needs,
* as a port, so the rules run over a fake directory in tests and over LDAPS
* (`ldapDirectory`, through `ldapts`) in a deployment.
*/
/** AD bind sub-codes by name (MS-ADTS; the `data <code>` in an LDAP 49 error). */
const AD_SUB_CODES = {
'52e': 'bad-password',
'775': 'locked',
'532': 'password-expired',
'773': 'must-change',
'533': 'disabled',
'701': 'account-expired',
};
/**
* What an AD bind sub-code means: `52e` bad password, `775` locked, `532`
* password expired, `773` must change at next logon, `533` disabled, `701`
* account expired; anything else (`525` no such user, `530`/`531` logon
* hours/workstation, a code a later AD invents) is `'unknown'`.
*/
export function adSubCodeName(code) {
const known = Object.prototype.hasOwnProperty.call(AD_SUB_CODES, code.toLowerCase());
return known ? AD_SUB_CODES[code.toLowerCase()] : 'unknown';
}
/**
* RFC 4515 §3: escape a value for an LDAP search filter. A string escapes `*`,
* `(`, `)`, `\` and NUL (and every non-ASCII byte, so nothing depends on how a
* server reads UTF-8 in a filter); bytes are escaped whole.
*/
export function escapeFilterValue(value) {
const bytes = typeof value === 'string' ? Buffer.from(value, 'utf8') : value;
let out = '';
for (const byte of bytes) {
const plain = byte >= 0x20 &&
byte < 0x7f &&
byte !== 0x2a &&
byte !== 0x28 &&
byte !== 0x29 &&
byte !== 0x5c;
out += plain ? String.fromCharCode(byte) : `\\${byte.toString(16).padStart(2, '0')}`;
}
return out;
}
/**
* A SID in SDDL string form (`S-1-5-21-…-1104`) as the binary `objectSid` a
* filter compares, or `undefined` when it is not one.
*/
export function sidToBytes(sid) {
const parts = /^S-1-(\d+)((?:-\d+){0,15})$/.exec(sid);
if (parts === null)
return undefined;
const authority = BigInt(parts[1]);
const subs = parts[2]
.split('-')
.filter((p) => p.length > 0)
.map(Number);
if (authority >= 2n ** 48n || subs.some((n) => !Number.isInteger(n) || n < 0 || n > 0xffffffff)) {
return undefined;
}
const out = Buffer.alloc(8 + subs.length * 4);
out[0] = 1;
out[1] = subs.length;
for (let i = 0; i < 6; i += 1)
out[2 + i] = Number((authority >> BigInt(8 * (5 - i))) & 0xffn);
subs.forEach((n, i) => out.writeUInt32LE(n, 8 + i * 4));
return out;
}
//# sourceMappingURL=port.js.map