| // Copyright 2018 The Casbin Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| import { CoreEnforcer } from './coreEnforcer'; |
| import { BatchAdapter } from './persist'; |
| import { UpdatableAdapter } from './persist'; |
| import { PolicyOp } from './model'; |
| |
| /** |
| * InternalEnforcer = CoreEnforcer + Internal API. |
| */ |
| export class InternalEnforcer extends CoreEnforcer { |
| /** |
| * addPolicyInternal adds a rule to the current policy. |
| */ |
| public async addPolicyInternal(sec: string, ptype: string, rule: string[]): Promise<boolean> { |
| if (this.model.hasPolicy(sec, ptype, rule)) { |
| return false; |
| } |
| |
| if (this.adapter && this.autoSave) { |
| try { |
| await this.adapter.addPolicy(sec, ptype, rule); |
| } catch (e) { |
| if (e.message !== 'not implemented') { |
| throw e; |
| } |
| } |
| } |
| |
| if (this.watcher && this.autoNotifyWatcher) { |
| // error intentionally ignored |
| this.watcher.update(); |
| } |
| |
| const ok = this.model.addPolicy(sec, ptype, rule); |
| |
| if (sec === 'g' && ok) { |
| await this.buildIncrementalRoleLinks(PolicyOp.PolicyAdd, ptype, [rule]); |
| } |
| return ok; |
| } |
| |
| // addPolicies adds rules to the current policy. |
| // removePolicies removes rules from the current policy. |
| public async addPoliciesInternal(sec: string, ptype: string, rules: string[][]): Promise<boolean> { |
| for (const rule of rules) { |
| if (this.model.hasPolicy(sec, ptype, rule)) { |
| return false; |
| } |
| } |
| |
| if (this.autoSave) { |
| if ('addPolicies' in this.adapter) { |
| try { |
| await (this.adapter as BatchAdapter).addPolicies(sec, ptype, rules); |
| } catch (e) { |
| if (e.message !== 'not implemented') { |
| throw e; |
| } |
| } |
| } else { |
| throw new Error('cannot to save policy, the adapter does not implement the BatchAdapter'); |
| } |
| } |
| |
| if (this.watcher && this.autoNotifyWatcher) { |
| // error intentionally ignored |
| this.watcher.update(); |
| } |
| |
| 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; |
| } |
| |
| /** |
| * updatePolicyInternal updates a rule from the current policy. |
| */ |
| public async updatePolicyInternal(sec: string, ptype: string, oldRule: string[], newRule: string[]): Promise<boolean> { |
| if (!this.model.hasPolicy(sec, ptype, oldRule)) { |
| return false; |
| } |
| |
| if (this.autoSave) { |
| if ('updatePolicy' in this.adapter) { |
| try { |
| await (this.adapter as UpdatableAdapter).updatePolicy(sec, ptype, oldRule, newRule); |
| } catch (e) { |
| if (e.message !== 'not implemented') { |
| throw e; |
| } |
| } |
| } else { |
| throw new Error('cannot to update policy, the adapter does not implement the UpdatableAdapter'); |
| } |
| } |
| |
| if (this.watcher && this.autoNotifyWatcher) { |
| // In fact I think it should wait for the respond, but they implement add_policy() like this |
| // error intentionally ignored |
| this.watcher.update(); |
| } |
| |
| 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; |
| } |
| |
| /** |
| * removePolicyInternal removes a rule from the current policy. |
| */ |
| public async removePolicyInternal(sec: string, ptype: string, rule: string[]): Promise<boolean> { |
| if (!this.model.hasPolicy(sec, ptype, rule)) { |
| return false; |
| } |
| |
| if (this.adapter && this.autoSave) { |
| try { |
| await this.adapter.removePolicy(sec, ptype, rule); |
| } catch (e) { |
| if (e.message !== 'not implemented') { |
| throw e; |
| } |
| } |
| } |
| |
| if (this.watcher && this.autoNotifyWatcher) { |
| // error intentionally ignored |
| this.watcher.update(); |
| } |
| |
| const ok = await this.model.removePolicy(sec, ptype, rule); |
| if (sec === 'g' && ok) { |
| await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, [rule]); |
| } |
| return ok; |
| } |
| |
| // removePolicies removes rules from the current policy. |
| public async removePoliciesInternal(sec: string, ptype: string, rules: string[][]): Promise<boolean> { |
| for (const rule of rules) { |
| if (!this.model.hasPolicy(sec, ptype, rule)) { |
| return false; |
| } |
| } |
| |
| if (this.autoSave) { |
| if ('removePolicies' in this.adapter) { |
| try { |
| await (this.adapter as BatchAdapter).removePolicies(sec, ptype, rules); |
| } catch (e) { |
| if (e.message !== 'not implemented') { |
| throw e; |
| } |
| } |
| } else { |
| throw new Error('cannot to save policy, the adapter does not implement the BatchAdapter'); |
| } |
| } |
| |
| if (this.watcher && this.autoNotifyWatcher) { |
| // error intentionally ignored |
| this.watcher.update(); |
| } |
| |
| const [ok, effects] = this.model.removePolicies(sec, ptype, rules); |
| if (sec === 'g' && ok && effects?.length) { |
| await this.buildIncrementalRoleLinks(PolicyOp.PolicyRemove, ptype, effects); |
| } |
| return ok; |
| } |
| |
| /** |
| * removeFilteredPolicyInternal removes rules based on field filters from the current policy. |
| */ |
| public async removeFilteredPolicyInternal(sec: string, ptype: string, fieldIndex: number, fieldValues: string[]): Promise<boolean> { |
| if (this.adapter && this.autoSave) { |
| try { |
| await this.adapter.removeFilteredPolicy(sec, ptype, fieldIndex, ...fieldValues); |
| } catch (e) { |
| if (e.message !== 'not implemented') { |
| throw e; |
| } |
| } |
| } |
| |
| if (this.watcher && this.autoNotifyWatcher) { |
| // error intentionally ignored |
| this.watcher.update(); |
| } |
| |
| 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; |
| } |
| } |