diff --git a/src/policy.ts b/src/policy.ts new file mode 100644 index 0000000..91a2534 --- /dev/null +++ b/src/policy.ts @@ -0,0 +1,93 @@ +// Copyright 2024 The Casdoor 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 { AxiosResponse } from 'axios' +import { Config } from './config' +import Request from './request' +import { Enforcer } from './enforcer' + +export interface Policy { + Id: number + Ptype: string + V0: string + V1: string + V2: string + V3?: string + V4?: string + V5?: string + tableName?: string +} + +export class PolicySDK { + private config: Config + private readonly request: Request + + constructor(config: Config, request: Request) { + this.config = config + this.request = request + } + + public async getPolicies(enforcerName: string, adapterId?: string) { + if (!this.request) { + throw new Error('request init failed') + } + + return (await this.request.get('/get-policies', { + params: { + id: `${this.config.orgName}/${enforcerName}`, + adapterId: adapterId, + }, + })) as unknown as Promise> + } + + public async modifyPolicy( + method: string, + enforcer: Enforcer, + policies: Policy[], + ) { + if (!this.request) { + throw new Error('request init failed') + } + + let data + if (method === 'update-policy') { + data = JSON.stringify(policies) + } else { + data = JSON.stringify(policies[0]) + } + + const url = `/${method}` + return (await this.request.post(url, data, { + params: { + id: `${enforcer.owner}/${enforcer.name}`, + }, + })) as unknown as Promise>> + } + + public async addPolicy(enforcer: Enforcer, policy: Policy) { + return this.modifyPolicy('add-policy', enforcer, [policy]) + } + + public async updatePolicy( + enforcer: Enforcer, + oldPolicy: Policy, + newPolicy: Policy, + ) { + return this.modifyPolicy('update-policy', enforcer, [oldPolicy, newPolicy]) + } + + public async deletePolicy(enforcer: Enforcer, policy: Policy) { + return this.modifyPolicy('remove-policy', enforcer, [policy]) + } +} diff --git a/src/sdk.ts b/src/sdk.ts index 1827caa..ad80d40 100644 --- a/src/sdk.ts +++ b/src/sdk.ts @@ -27,6 +27,7 @@ import { Session, SessionSDK } from './session' import { Syncer, SyncerSDK } from './syncer' import { Permission, PermissionSDK } from './permission' import { Plan, PlanSDK } from './plan' +import { Policy, PolicySDK } from './policy' import { Pricing, PricingSDK } from './pricing' import { Provider, ProviderSDK } from './provider' import { Resource, ResourceSDK } from './resource' @@ -58,6 +59,7 @@ export class SDK { private syncerSDK: SyncerSDK private permissionSDK: PermissionSDK private planSDK: PlanSDK + private policySDK: PolicySDK private pricingSDK: PricingSDK private providerSDK: ProviderSDK private resourceSDK: ResourceSDK @@ -99,6 +101,7 @@ export class SDK { this.syncerSDK = new SyncerSDK(this.config, this.request) this.permissionSDK = new PermissionSDK(this.config, this.request) this.planSDK = new PlanSDK(this.config, this.request) + this.policySDK = new PolicySDK(this.config, this.request) this.pricingSDK = new PricingSDK(this.config, this.request) this.providerSDK = new ProviderSDK(this.config, this.request) this.resourceSDK = new ResourceSDK(this.config, this.request) @@ -390,6 +393,26 @@ export class SDK { return await this.planSDK.deletePlan(plan) } + public async getPolicies(enforcerName: string, adapterId?: string) { + return await this.policySDK.getPolicies(enforcerName, adapterId) + } + + public async addPolicy(enforcer: Enforcer, policy: Policy) { + return await this.policySDK.addPolicy(enforcer, policy) + } + + public async updatePolicy( + enforcer: Enforcer, + oldPolicy: Policy, + newPolicy: Policy, + ) { + return await this.policySDK.updatePolicy(enforcer, oldPolicy, newPolicy) + } + + public async deletePolicy(enforcer: Enforcer, policy: Policy) { + return await this.policySDK.deletePolicy(enforcer, policy) + } + public async getPricings() { return await this.pricingSDK.getPricings() } diff --git a/test/policy.test.ts b/test/policy.test.ts new file mode 100644 index 0000000..20d28d1 --- /dev/null +++ b/test/policy.test.ts @@ -0,0 +1,121 @@ +// Copyright 2024 The Casdoor 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 { SDK } from '../src' +import * as util from './util' +import { Config } from '../src/config' +import { Policy } from '../src/policy' +import { Enforcer } from '../src/enforcer' + +test('TestPolicy', async () => { + const testConfig: Config = { + endpoint: util.TestCasdoorEndpoint, + clientId: util.TestClientId, + clientSecret: util.TestClientSecret, + certificate: util.TestJwtPublicKey, + orgName: util.TestCasdoorOrganization, + appName: util.TestCasdoorApplication, + } + const sdk = new SDK(testConfig) + + const name = util.getRandomName('policy') + + const enforcer: Enforcer = { + owner: 'admin', + name: name, + createdTime: new Date().toISOString(), + displayName: name, + model: 'built-in/user-model-built-in', + adapter: 'built-in/user-adapter-built-in', + description: 'Casdoor Website', + } + + // Add a new object + const policy: Policy = { + Id: 0, + Ptype: 'p', + V0: '1', + V1: '2', + V2: '4', + } + + const newPolicy: Policy = { + Id: 0, + Ptype: 'p', + V0: '1', + V1: '2', + V2: '5', + } + + const { data: enforcerAddResponse } = await sdk.addEnforcer(enforcer) + if (enforcerAddResponse.data !== 'Affected') { + throw new Error('Failed to add enforcer') + } + + const { data: addResponse } = await sdk.addPolicy(enforcer, policy) + if (addResponse.data !== 'Affected') { + throw new Error('Failed to add object') + } + + // Get all objects and check if our added object is in the list + const { + data: { data: policies }, + } = await sdk.getPolicies(enforcer.name) + const found = policies.some((item) => item.Id === 0 && item.V2 === '4') + if (!found) { + throw new Error('Added object not found in list') + } + + // Update the object + const { data: updateResponse } = await sdk.updatePolicy( + enforcer, + policy, + newPolicy, + ) + if (updateResponse.data !== 'Affected') { + throw new Error('Failed to update object') + } + + // ValIdate the update + const { + data: { data: updatedPolicies }, + } = await sdk.getPolicies(name) + const updatedfound = updatedPolicies.some( + (item) => item.Id === 0 && item.V2 === '5', + ) + if (!updatedfound) { + throw new Error( + `Failed to update object, description mismatch: ${policy.V2} != ${newPolicy.V2}`, + ) + } + + // Delete the object + const { data: deleteResponse } = await sdk.deletePolicy(enforcer, newPolicy) + if (deleteResponse.data !== 'Affected') { + throw new Error('Failed to delete object') + } + + // ValIdate the deletion + const { + data: { data: deletedPolicies }, + } = await sdk.getPolicies(name) + const deletedfound = deletedPolicies.some((item) => item === newPolicy) + if (deletedfound) { + throw new Error( + `Failed to delete object, it's still retrievable ${JSON.stringify( + deletedPolicies, + )}`, + ) + } +})