diff --git a/src/internalEnforcer.ts b/src/internalEnforcer.ts index 3eeb759..b4bba9a 100644 --- a/src/internalEnforcer.ts +++ b/src/internalEnforcer.ts @@ -29,6 +29,7 @@ export class InternalEnforcer extends CoreEnforcer { return false; } + // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { try { await this.adapter.addPolicy(sec, ptype, rule); @@ -67,7 +68,8 @@ export class InternalEnforcer extends CoreEnforcer { } } - if (this.autoSave) { + // Persist when an adapter is configured and autoSave is enabled. + if (this.adapter && this.autoSave) { if ('addPolicies' in this.adapter) { try { await this.adapter.addPolicies(sec, ptype, rules); @@ -113,7 +115,8 @@ export class InternalEnforcer extends CoreEnforcer { return false; } - if (this.autoSave) { + // Persist when an adapter is configured and autoSave is enabled. + if (this.adapter && this.autoSave) { if ('addPolicies' in this.adapter) { try { await this.adapter.addPolicies(sec, ptype, newRules); @@ -158,8 +161,8 @@ export class InternalEnforcer extends CoreEnforcer { if (!this.model.hasPolicy(sec, ptype, oldRule)) { return false; } - - if (this.autoSave) { + // Persist when an adapter is configured and autoSave is enabled. + if (this.adapter && this.autoSave) { if ('updatePolicy' in this.adapter) { try { await this.adapter.updatePolicy(sec, ptype, oldRule, newRule); @@ -200,6 +203,7 @@ export class InternalEnforcer extends CoreEnforcer { return false; } + // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { try { await this.adapter.removePolicy(sec, ptype, rule); @@ -236,7 +240,8 @@ export class InternalEnforcer extends CoreEnforcer { } } - if (this.autoSave) { + // Persist when an adapter is configured and autoSave is enabled. + if (this.adapter && this.autoSave) { if ('removePolicies' in this.adapter) { try { await this.adapter.removePolicies(sec, ptype, rules); @@ -278,6 +283,7 @@ export class InternalEnforcer extends CoreEnforcer { fieldValues: string[], useWatcher: boolean ): Promise { + // Persist when an adapter is configured and autoSave is enabled. if (this.adapter && this.autoSave) { try { await this.adapter.removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues); @@ -320,4 +326,110 @@ export class InternalEnforcer extends CoreEnforcer { const assertion = this.model.model.get('p')?.get(ptype); assertion?.fieldIndexMap.set(field, index); } + + protected async addPolicyWithoutNotify(sec: string, ptype: string, rule: string[]): Promise { + if (this.model.hasPolicy(sec, ptype, rule)) { + return false; + } + + const ok = this.model.addPolicy(sec, ptype, rule); + if (sec === 'g' && ok) { + await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [rule]); + } + return ok; + } + + protected async addPoliciesWithoutNotify(sec: string, ptype: string, rules: string[][]): Promise { + for (const rule of rules) { + if (this.model.hasPolicy(sec, ptype, rule)) { + return false; + } + } + + const [ok, effects] = await this.model.addPolicies(sec, ptype, rules); + if (sec === 'g' && ok && effects?.length) { + await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, effects); + } + return ok; + } + + protected async addPoliciesWithoutNotifyEx(sec: string, ptype: string, rules: string[][]): Promise { + const newRules = rules.filter((rule) => !this.model.hasPolicy(sec, ptype, rule)); + if (newRules.length === 0) { + return false; + } + + const [ok, effects] = await this.model.addPolicies(sec, ptype, newRules); + if (sec === 'g' && ok && effects?.length) { + await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, effects); + } + return ok; + } + + protected async updatePolicyWithoutNotify(sec: string, ptype: string, oldRule: string[], newRule: string[]): Promise { + if (!this.model.hasPolicy(sec, ptype, oldRule)) { + return false; + } + + const ok = this.model.updatePolicy(sec, ptype, oldRule, newRule); + if (sec === 'g' && ok) { + await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [oldRule]); + await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [newRule]); + } + return ok; + } + + protected async removePolicyWithoutNotify(sec: string, ptype: string, rule: string[]): Promise { + if (!this.model.hasPolicy(sec, ptype, rule)) { + return false; + } + + const ok = await this.model.removePolicy(sec, ptype, rule); + if (sec === 'g' && ok) { + await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [rule]); + } + return ok; + } + + protected async removePoliciesWithoutNotify(sec: string, ptype: string, rules: string[][]): Promise { + for (const rule of rules) { + if (!this.model.hasPolicy(sec, ptype, rule)) { + return false; + } + } + + const [ok, effects] = this.model.removePolicies(sec, ptype, rules); + if (sec === 'g' && ok && effects?.length) { + await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects); + } + return ok; + } + + protected async removeFilteredPolicyWithoutNotify( + sec: string, + ptype: string, + fieldIndex: number, + fieldValues: string[] + ): Promise { + const [ok, effects] = this.model.removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues); + if (sec === 'g' && ok && effects?.length) { + await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects); + } + return ok; + } + + protected async updatePoliciesWithoutNotify(sec: string, ptype: string, oldRules: string[][], newRules: string[][]): Promise { + // Mirror the Go updatePoliciesWithoutNotify; reuse the existing internal flow. + // Because updatePoliciesInternal isn't implemented yet, fall back to per-item updates. + if (oldRules.length !== newRules.length) { + throw new Error('the length of oldRules should be equal to the length of newRules'); + } + for (let i = 0; i < oldRules.length; i++) { + const ok = await this.updatePolicyWithoutNotify(sec, ptype, oldRules[i], newRules[i]); + if (!ok) { + return false; + } + } + return true; + } } diff --git a/src/managementEnforcer.ts b/src/managementEnforcer.ts index 2d8bea1..f5d0025 100644 --- a/src/managementEnforcer.ts +++ b/src/managementEnforcer.ts @@ -589,28 +589,31 @@ export class ManagementEnforcer extends InternalEnforcer { public async addFunction(name: string, func: MatchingFunction): Promise { this.fm.addFunction(name, func); } - public async selfAddPolicy(sec: string, ptype: string, rule: string[]): Promise { - return this.addPolicyInternal(sec, ptype, rule, false); + return this.addPolicyWithoutNotify(sec, ptype, rule); + } + + public async selfAddPolicies(sec: string, ptype: string, rules: string[][]): Promise { + return this.addPoliciesWithoutNotify(sec, ptype, rules); } public async selfRemovePolicy(sec: string, ptype: string, rule: string[]): Promise { - return this.removePolicyInternal(sec, ptype, rule, false); + return this.removePolicyWithoutNotify(sec, ptype, rule); } - public async selfRemoveFilteredPolicy(sec: string, ptype: string, fieldIndex: number, fieldValues: string[]): Promise { - return this.removeFilteredPolicyInternal(sec, ptype, fieldIndex, fieldValues, false); + public async selfRemovePolicies(sec: string, ptype: string, rules: string[][]): Promise { + return this.removePoliciesWithoutNotify(sec, ptype, rules); } - public async selfUpdatePolicy(sec: string, ptype: string, oldRule: string[], newRule: string[]): Promise { - return this.updatePolicyInternal(sec, ptype, oldRule, newRule, false); + public async selfRemoveFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string[]): Promise { + return this.removeFilteredPolicyWithoutNotify(sec, ptype, fieldIndex, fieldValues); } - public async selfAddPolicies(sec: string, ptype: string, rule: string[][]): Promise { - return this.addPoliciesInternal(sec, ptype, rule, false); + public async selfUpdatePolicy(sec: string, ptype: string, oldRule: string[], newRule: string[]): Promise { + return this.updatePolicyWithoutNotify(sec, ptype, oldRule, newRule); } - public async selfRemovePolicies(sec: string, ptype: string, rule: string[][]): Promise { - return this.removePoliciesInternal(sec, ptype, rule, false); + public async selfUpdatePolicies(sec: string, ptype: string, oldRules: string[][], newRules: string[][]): Promise { + return this.updatePoliciesWithoutNotify(sec, ptype, oldRules, newRules); } }