UNPKG

@fajarnugraha37/nope-iam

Version:

A highly extensible, type-safe IAM-like access control library for Node.js, inspired by AWS IAM. Deny by default, allow by vibes and less patience for your bad access patterns. Supports policies, roles, decorators, adapters, and rich evaluation context be

139 lines 5.71 kB
import { IAM } from '../core/iam.js'; export function LogAccess(opts) { return (target, propertyKey, descriptor) => { const original = descriptor.value; descriptor.value = async function (...args) { const logger = this?.logger || this?.iam?.logger || console; let result = undefined; let error = undefined; try { result = await original.apply(this, args); if (logger) { const ctx = { user: this.user, args, result, method: typeof propertyKey === 'symbol' ? propertyKey.toString() : String(propertyKey), class: target.constructor?.name, }; let msg = opts?.message; if (typeof msg === 'function') msg = msg(ctx); if (!msg) msg = `Access attempt: user=${ctx.user?.id}, method=${ctx.method}, result=${JSON.stringify(result)}`; if (typeof logger[opts?.logLevel || 'info'] === 'function') { logger[opts?.logLevel || 'info'](msg, ctx); } else { console.log(msg, ctx); } } return result; } catch (err) { error = err; if (logger) { const ctx = { user: this.user, args, error, method: typeof propertyKey === 'symbol' ? propertyKey.toString() : String(propertyKey), class: target.constructor?.name, }; let msg = opts?.message; if (typeof msg === 'function') msg = msg(ctx); if (!msg) msg = `Access denied: user=${ctx.user?.id}, method=${ctx.method}, error=${error?.message}`; if (typeof logger[opts?.logLevel || 'warn'] === 'function') { logger[opts?.logLevel || 'warn'](msg, ctx); } else { console.warn(msg, ctx); } } throw err; } }; return descriptor; }; } export function AllowActions(actions, resources) { return (target, propertyKey, descriptor) => { const original = descriptor.value; descriptor.value = async function (...args) { const iam = this?.iam || global.iam; if (!iam) throw new Error('IAM instance not found'); const resourceList = Array.isArray(resources) ? resources : [resources]; for (const action of actions) { for (const resource of resourceList) { const result = await iam.can({ user: this.user, action, resource }); if (result.decision) { return original.apply(this, args); } } } throw new Error('Access denied: none of the actions/resources allowed'); }; return descriptor; }; } export function DenyActions(actions, resources) { return (target, propertyKey, descriptor) => { const original = descriptor.value; descriptor.value = async function (...args) { const iam = this?.iam || global.iam; if (!iam) throw new Error('IAM instance not found'); const resourceList = Array.isArray(resources) ? resources : [resources]; for (const action of actions) { for (const resource of resourceList) { const result = await iam.can({ user: this.user, action, resource }); if (result.decision) throw new Error('Access denied: explicitly denied action'); } } return original.apply(this, args); }; return descriptor; }; } export function AccessCondition(condition) { return (target, propertyKey, descriptor) => { const original = descriptor.value; descriptor.value = function (...args) { if (!condition(this.user, ...args)) throw new Error('Access denied: condition failed'); return original.apply(this, args); }; return descriptor; }; } export function AccessControl(params) { return (target, propertyKey, descriptor) => { const original = descriptor.value; if (typeof original !== 'function') { throw new Error('AccessControl can only be applied to methods'); } descriptor.value = function (...args) { const iam = this?.iam || global.iam; if (!iam) throw new Error('IAM instance not found'); const canParams = typeof params === 'function' ? params.bind(this)(...args) : params; const { action = '', resource = '', context = {} } = canParams; return Promise.resolve(iam.can({ user: this.user, action: String(action), resource: String(resource), context })).then((result) => { if (!result.decision) throw new Error('Access denied'); return original.apply(this, args); }); }; return descriptor; }; } //# sourceMappingURL=accessControl.js.map