132 lines
4.5 KiB
JavaScript
132 lines
4.5 KiB
JavaScript
/**
|
|
* Security Context Entity - Domain Layer
|
|
*
|
|
* Represents security context for operations with validation and policy enforcement.
|
|
*
|
|
* @module v3/security/domain/entities
|
|
*/
|
|
import { randomUUID } from 'crypto';
|
|
/**
|
|
* Security Context - Entity
|
|
*/
|
|
export class SecurityContext {
|
|
_id;
|
|
_principalId;
|
|
_principalType;
|
|
_permissions;
|
|
_allowedPaths;
|
|
_blockedPaths;
|
|
_allowedCommands;
|
|
_blockedCommands;
|
|
_metadata;
|
|
_expiresAt;
|
|
_createdAt;
|
|
constructor(props) {
|
|
this._id = props.id ?? randomUUID();
|
|
this._principalId = props.principalId;
|
|
this._principalType = props.principalType;
|
|
this._permissions = new Set(props.permissions);
|
|
this._allowedPaths = new Set(props.allowedPaths ?? []);
|
|
this._blockedPaths = new Set(props.blockedPaths ?? []);
|
|
this._allowedCommands = new Set(props.allowedCommands ?? []);
|
|
this._blockedCommands = new Set(props.blockedCommands ?? []);
|
|
this._metadata = props.metadata ?? {};
|
|
this._expiresAt = props.expiresAt;
|
|
this._createdAt = props.createdAt ?? new Date();
|
|
}
|
|
static create(props) {
|
|
return new SecurityContext(props);
|
|
}
|
|
static fromPersistence(props) {
|
|
return new SecurityContext(props);
|
|
}
|
|
get id() { return this._id; }
|
|
get principalId() { return this._principalId; }
|
|
get principalType() { return this._principalType; }
|
|
get permissions() { return Array.from(this._permissions); }
|
|
get allowedPaths() { return Array.from(this._allowedPaths); }
|
|
get blockedPaths() { return Array.from(this._blockedPaths); }
|
|
get allowedCommands() { return Array.from(this._allowedCommands); }
|
|
get blockedCommands() { return Array.from(this._blockedCommands); }
|
|
get metadata() { return { ...this._metadata }; }
|
|
get expiresAt() { return this._expiresAt; }
|
|
get createdAt() { return new Date(this._createdAt); }
|
|
// Business Logic
|
|
hasPermission(level) {
|
|
return this._permissions.has(level) || this._permissions.has('admin');
|
|
}
|
|
isExpired() {
|
|
if (!this._expiresAt)
|
|
return false;
|
|
return Date.now() > this._expiresAt.getTime();
|
|
}
|
|
canAccessPath(path) {
|
|
if (this.isExpired())
|
|
return false;
|
|
// Check blocked paths first
|
|
for (const blocked of this._blockedPaths) {
|
|
if (path.startsWith(blocked) || this.matchGlob(path, blocked)) {
|
|
return false;
|
|
}
|
|
}
|
|
// If no allowed paths specified, allow all non-blocked
|
|
if (this._allowedPaths.size === 0)
|
|
return true;
|
|
// Check allowed paths
|
|
for (const allowed of this._allowedPaths) {
|
|
if (path.startsWith(allowed) || this.matchGlob(path, allowed)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
canExecuteCommand(command) {
|
|
if (this.isExpired())
|
|
return false;
|
|
const cmdBase = command.split(' ')[0];
|
|
// Check blocked commands first
|
|
if (this._blockedCommands.has(cmdBase) || this._blockedCommands.has(command)) {
|
|
return false;
|
|
}
|
|
// If no allowed commands specified, allow all non-blocked
|
|
if (this._allowedCommands.size === 0)
|
|
return true;
|
|
// Check allowed commands
|
|
return this._allowedCommands.has(cmdBase) || this._allowedCommands.has(command);
|
|
}
|
|
matchGlob(path, pattern) {
|
|
const regex = pattern
|
|
.replace(/\*\*/g, '.*')
|
|
.replace(/\*/g, '[^/]*')
|
|
.replace(/\?/g, '.');
|
|
return new RegExp(`^${regex}$`).test(path);
|
|
}
|
|
grantPermission(level) {
|
|
this._permissions.add(level);
|
|
}
|
|
revokePermission(level) {
|
|
this._permissions.delete(level);
|
|
}
|
|
addAllowedPath(path) {
|
|
this._allowedPaths.add(path);
|
|
}
|
|
addBlockedPath(path) {
|
|
this._blockedPaths.add(path);
|
|
}
|
|
toPersistence() {
|
|
return {
|
|
id: this._id,
|
|
principalId: this._principalId,
|
|
principalType: this._principalType,
|
|
permissions: Array.from(this._permissions),
|
|
allowedPaths: Array.from(this._allowedPaths),
|
|
blockedPaths: Array.from(this._blockedPaths),
|
|
allowedCommands: Array.from(this._allowedCommands),
|
|
blockedCommands: Array.from(this._blockedCommands),
|
|
metadata: this._metadata,
|
|
expiresAt: this._expiresAt?.toISOString(),
|
|
createdAt: this._createdAt.toISOString(),
|
|
};
|
|
}
|
|
}
|
|
//# sourceMappingURL=security-context.js.map
|