casbin/node-casbin

Sequelize v6 compatibility: addPolicies & removePolicies problem

Closed this issue · 13 comments

My database has a row
row1. ['userA', 'product', 'read']
I want to run function

addPolicies(
    ['userA', 'product', 'read'],
    ['userA', 'product', 'write']
)

I think the result should be
row1. ['userA', 'product', 'read']
row2. ['userA', 'product', 'write']
or

removePolicies(
    ['userA', 'product', 'read'],
    ['userA', 'product', 'write']
)

I think the result should be
no rows.

They're all return false
and database is not been effect

Is it intentional?

We need to resolve: node-casbin/sequelize-adapter#34 first

@fish0373 Which adapter are you using?

@nodece
I am using sequelize-adapter,
But its not support v6, your team is upgrading,
so, I copy sequelize-adapter source code to make it running.
Then, this problem is shown.
When you upgraded, I will change to use sequelize-adapter.

I'm not sure this problem has appear node-casbin or sequelize-adapter

adapter.ts

import { Adapter, Helper, Model } from 'casbin';
import { Sequelize, Options } from 'sequelize'
import { CasbinRule, CasbinRuleSchema } from './CasbinRule';

export class SequelizeAdapter implements Adapter {
  private option: Options;
  private sequelize!: Sequelize;

  constructor(option: Options) {
    this.option = option;
  }

  public static async newAdapter(option: Options): Promise<SequelizeAdapter> {
    const a = new SequelizeAdapter(option);
    await a.open();
    return a;
  }

  private async open(): Promise<void> {
    this.sequelize = new Sequelize(this.option);
    await this.sequelize.authenticate();
    CasbinRule.init(CasbinRuleSchema, { tableName: 'casbin_rule', sequelize: this.sequelize, freezeTableName: true })
    await this.createTable();
  }

  public async close(): Promise<void> {
    await this.sequelize.close();
  }

  private async createTable(): Promise<void> {
    await this.sequelize.sync();
  }

  private loadPolicyLine(line: CasbinRule, model: Model): void {
    const result = line.ptype + ', ' +
      [line.v0, line.v1, line.v2, line.v3, line.v4, line.v5].filter((n) => n).join(', ');
    Helper.loadPolicyLine(result, model);
  }

  public async loadPolicy(model: Model): Promise<void> {
    const lines = await this.sequelize.model('CasbinRule').findAll() as Array<CasbinRule>;

    for (const line of lines) {
      this.loadPolicyLine(line, model);
    }
  }

  private savePolicyLine(ptype: string, rule: string[]): CasbinRule {
    const line = new CasbinRule();
    line.ptype = ptype;
    if (rule.length > 0) line.v0 = rule[0];
    if (rule.length > 1) line.v1 = rule[1];
    if (rule.length > 2) line.v2 = rule[2];
    if (rule.length > 3) line.v3 = rule[3];
    if (rule.length > 4) line.v4 = rule[4];
    if (rule.length > 5) line.v5 = rule[5];
    return line;
  }

  public async savePolicy(model: Model): Promise<boolean> {
    await this.sequelize.transaction(async (tx) => {
      await this.sequelize.model('CasbinRule').destroy({ where: {}, truncate: true, transaction: tx });

      const lines: CasbinRule[] = [];
      ['p', 'g'].forEach((e) => {
        const astMap = model.model.get(e)!;
        for (const [ptype, ast] of astMap) {
          for (const rule of ast.policy) {
            const line = this.savePolicyLine(ptype, rule);
            lines.push(line);
          }
        }
      });

      await CasbinRule.bulkCreate(
        lines.map((l) => l.get({ plain: true })), { transaction: tx }
      )
    })
    return true;
  }

  public async addPolicy(
    sec: string,
    ptype: string,
    rule: string[]
  ) {
    const line = this.savePolicyLine(ptype, rule);
    await line.save();
  }

  public async addPolicies(sec: string, ptype: string, rules: string[][]): Promise<void> {
    const lines: CasbinRule[] = [];
    for (const rule of rules) {
      const line = this.savePolicyLine(ptype, rule);
      lines.push(line);
    }
    await this.sequelize.transaction(async (tx) => {
      await CasbinRule.bulkCreate(
        lines.map((l) => l.get({ plain: true })), { transaction: tx }
      );
    });
  }

  public async removePolicy(sec: string, ptype: string, rule: string[],): Promise<void> {
    const line = this.savePolicyLine(ptype, rule);
    const where = {};
    Object.keys(line.get({ plain: true }))
      .filter((key) => key !== 'id')
      .forEach((key) => {
        // @ts-ignore
        where[key] = line[key];
      })
    await this.sequelize.model('CasbinRule').destroy({ where });
  }

  public async removePolicies(sec: string, ptype: string, rules: string[][]): Promise<void> {
    await this.sequelize.transaction(async (tx) => {
      for (const rule of rules) {
        const line = this.savePolicyLine(ptype, rule);
        const where = {};

        Object.keys(line.get({ plain: true }))
          .filter((key) => key !== 'id')
          .forEach((key) => {
            // @ts-ignore
            where[key] = line[key];
          })

        await this.sequelize.model('CasbinRule').destroy({ where, transaction: tx });
      }
    })
  }

  public async removeFilteredPolicy(sec: string, ptype: string, fieldIndex: number, ...fieldValues: string[]): Promise<void> {
    const line = new CasbinRule();

    const idx = fieldIndex + fieldValues.length;
    if (fieldIndex <= 0 && 0 < idx) line.v0 = fieldValues[0 - fieldIndex];
    if (fieldIndex <= 1 && 1 < idx) line.v1 = fieldValues[1 - fieldIndex];
    if (fieldIndex <= 2 && 2 < idx) line.v2 = fieldValues[2 - fieldIndex];
    if (fieldIndex <= 3 && 3 < idx) line.v3 = fieldValues[3 - fieldIndex];
    if (fieldIndex <= 4 && 4 < idx) line.v4 = fieldValues[4 - fieldIndex];
    if (fieldIndex <= 5 && 5 < idx) line.v5 = fieldValues[5 - fieldIndex];

    const where = {};

    Object.keys(line.get({ plain: true }))
      .filter((key) => key !== 'id')
      .forEach((key) => {
        // @ts-ignore
        where[key] = line[key]
      })

    await this.sequelize.model('CasbinRule').destroy({ where })
  }
}

casbinRule.ts

import { DataTypes, Model, Optional, ModelAttributes } from 'sequelize';

interface CasbinRuleAttributes {
  ptype: string;
  v0: string;
  v1: string;
  v2: string;
  v3: string;
  v4: string;
  v5: string;
}

interface CasbinRuleCreationAttributes extends Optional<CasbinRuleAttributes, 'ptype'> { }

export class CasbinRule extends Model<CasbinRuleAttributes, CasbinRuleCreationAttributes> implements CasbinRuleAttributes {
  public ptype!: string;
  public v0!: string;
  public v1!: string;
  public v2!: string;
  public v3!: string;
  public v4!: string;
  public v5!: string;
}

export const CasbinRuleSchema: ModelAttributes = {
  ptype: {
    type: DataTypes.STRING,
  },
  v0: {
    type: DataTypes.STRING,
  },
  v1: {
    type: DataTypes.STRING,
  },
  v2: {
    type: DataTypes.STRING,
  },
  v3: {
    type: DataTypes.STRING,
  },
  v4: {
    type: DataTypes.STRING,
  },
  v5: {
    type: DataTypes.STRING,
  },
}

export default CasbinRule;

@fish0373 It seems to be a bug of the sequelize-adapter.

@fish0373

We can try latest sequelize-typescript 2.0.0-beta.1 (a month ago) with sequelize >=6.2, see: sequelize/sequelize-typescript#856

image

@hsluoyz Is there any guide for setup of code on local machine and any contribution.md as I am not getting hang of the code
Acc to me I have to fix the function addPolicies at https://github.com/casbin/node-casbin/blob/master/src/model/model.ts

@fish0373

We can try latest sequelize-typescript 2.0.0-beta.1 (a month ago) with sequelize >=6.2, see: RobinBuschmann/sequelize-typescript#856

image

@nodece , @hsluoyz I have made the changes mentioned in this comment , @fish0373 can you please tell me how to recreate this error on my local machine so that I can check if this fixed it.

@hsluoyz @nodece resolved the issue mentioned above ,
Working on this one.

@fish0373 Sequelize v6 is supported in latest casbin-sequelize-adapter v2.2.0: https://www.npmjs.com/package/casbin-sequelize-adapter/v/2.2.0

Plz try again.