Skip to content

Commit a19bd09

Browse files
committed
fix: ensures packRule helper doesn't stuck inside infinite loop when invalid parameters are passed
Fixes #705
1 parent 4e01d02 commit a19bd09

File tree

2 files changed

+40
-49
lines changed

2 files changed

+40
-49
lines changed
Lines changed: 36 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import './spec_helper'
21
import { packRules, unpackRules } from '../src/extra'
32

43
describe('Ability rules packing', () => {
@@ -9,81 +8,81 @@ describe('Ability rules packing', () => {
98
{ action: 'delete', subject: 'Post' }
109
])
1110

12-
expect(rules.every(Array.isArray)).to.be.true
11+
expect(rules.every(Array.isArray)).toBe(true)
1312
})
1413

1514
it('puts `actions` as 1st element of rule array', () => {
1615
const rules = packRules([{ action: 'read', subject: 'Post' }])
1716

18-
expect(rules[0][0]).to.equal('read')
19-
expect(rules[0]).to.have.length(2)
17+
expect(rules[0][0]).toBe('read')
18+
expect(rules[0]).toHaveLength(2)
2019
})
2120

2221
it('joins `actions` with comma if its value is an array', () => {
2322
const rules = packRules([{ action: ['read', 'update'], subject: 'Post' }])
2423

25-
expect(rules[0][0]).to.equal('read,update')
26-
expect(rules[0]).to.have.length(2)
24+
expect(rules[0][0]).toBe('read,update')
25+
expect(rules[0]).toHaveLength(2)
2726
})
2827

2928
it('puts `subject` as 2nd element of rule array', () => {
3029
const rules = packRules([{ action: 'read', subject: 'Post' }])
3130

32-
expect(rules[0][1]).to.equal('Post')
33-
expect(rules[0]).to.have.length(2)
31+
expect(rules[0][1]).toBe('Post')
32+
expect(rules[0]).toHaveLength(2)
3433
})
3534

3635
it('puts `subject` with comma if its value is an array', () => {
3736
const rules = packRules([{ action: 'read', subject: ['Post', 'Comment'] }])
3837

39-
expect(rules[0][1]).to.equal('Post,Comment')
40-
expect(rules[0]).to.have.length(2)
38+
expect(rules[0][1]).toBe('Post,Comment')
39+
expect(rules[0]).toHaveLength(2)
4140
})
4241

4342
it('puts `conditions` as 3rd element of rule array', () => {
4443
const conditions = { private: true }
4544
const rules = packRules([{ action: 'read', subject: 'Post', conditions }])
4645

47-
expect(rules[0][2]).to.equal(conditions)
48-
expect(rules[0]).to.have.length(3)
46+
expect(rules[0][2]).toBe(conditions)
47+
expect(rules[0]).toHaveLength(3)
4948
})
5049

5150
it('puts `0` in place of `conditions` if they are not defined but `fields` are defined', () => {
5251
const rules = packRules([{ action: 'read', subject: 'Post', fields: ['title'] }])
5352

54-
expect(rules[0][2]).to.equal(0)
55-
expect(rules[0]).to.have.length(5)
53+
expect(rules[0][2]).toBe(0)
54+
expect(rules[0]).toHaveLength(5)
5655
})
5756

5857
it('converts `inverted` to number and puts it as 4th element of rule array', () => {
5958
const rules = packRules([{ action: 'read', subject: 'Post', inverted: true }])
6059

61-
expect(rules[0][3]).to.equal(1)
62-
expect(rules[0]).to.have.length(4)
60+
expect(rules[0][3]).toBe(1)
61+
expect(rules[0]).toHaveLength(4)
6362
})
6463

6564
it('joins `fields` and puts it as 5th element of rule array', () => {
6665
const fields = ['title', 'description']
6766
const rules = packRules([{ action: 'read', subject: 'Post', fields }])
6867

69-
expect(rules[0][4]).to.equal(fields.join(','))
70-
expect(rules[0]).to.have.length(5)
68+
expect(rules[0][4]).toBe(fields.join(','))
69+
expect(rules[0]).toHaveLength(5)
7170
})
7271

7372
it('puts `0` in place of `fields` when reason is provided and fields are not', () => {
7473
const reason = 'forbidden reason'
7574
const rules = packRules([{ action: 'read', subject: 'Post', reason }])
7675

77-
expect(rules[0][4]).to.equal(0)
78-
expect(rules[0]).to.have.length(6)
76+
expect(rules[0][4]).toBe(0)
77+
expect(rules[0]).toHaveLength(6)
7978
})
8079

8180
it('puts `reason` as 6th element of rule array', () => {
8281
const reason = 'forbidden reason'
8382
const rules = packRules([{ action: 'read', subject: 'Post', reason }])
8483

85-
expect(rules[0][5]).to.equal(reason)
86-
expect(rules[0]).to.have.length(6)
84+
expect(rules[0][5]).toBe(reason)
85+
expect(rules[0]).toHaveLength(6)
8786
})
8887
})
8988

@@ -94,82 +93,82 @@ describe('Ability rules packing', () => {
9493
['delete', 'Post']
9594
])
9695

97-
expect(rules.every(rule => typeof rule === 'object')).to.be.true
96+
expect(rules.every(rule => typeof rule === 'object')).toBe(true)
9897
})
9998

10099
it('puts 1st element under `actions` field and converts it to an array', () => {
101100
const rules = unpackRules([['read,update', 'Post']])
102101

103-
expect(rules[0].action).to.deep.equal(['read', 'update'])
102+
expect(rules[0].action).toEqual(['read', 'update'])
104103
})
105104

106105
it('converts even a single `action` to an array', () => {
107106
const rules = unpackRules([['read', 'Post']])
108107

109-
expect(rules[0].action).to.deep.equal(['read'])
108+
expect(rules[0].action).toEqual(['read'])
110109
})
111110

112111
it('puts 2nd element under `subject` field and converts it to an array', () => {
113112
const rules = unpackRules([['read', 'Post,Comment']])
114113

115-
expect(rules[0].subject).to.deep.equal(['Post', 'Comment'])
114+
expect(rules[0].subject).toEqual(['Post', 'Comment'])
116115
})
117116

118117
it('converts even a single `subject` to an array', () => {
119118
const rules = unpackRules([['read', 'Post']])
120119

121-
expect(rules[0].subject).to.deep.equal(['Post'])
120+
expect(rules[0].subject).toEqual(['Post'])
122121
})
123122

124123
it('puts 3rd element under `conditions` field', () => {
125124
const conditions = { private: true }
126125
const rules = unpackRules([['read', 'Post,Comment', conditions]])
127126

128-
expect(rules[0].conditions).to.equal(conditions)
127+
expect(rules[0].conditions).toBe(conditions)
129128
})
130129

131130
it('converts `conditions` to `undefined` if its value is `0`', () => {
132131
const rules = unpackRules([['read', 'Post,Comment', 0, 1]])
133132

134-
expect(rules[0].conditions).to.be.undefined
133+
expect(rules[0].conditions).toBe(undefined)
135134
})
136135

137136
it('puts 4th element under `inverted` field and converts it to boolean', () => {
138137
const rules = unpackRules([['read', 'Post,Comment', 0, 1]])
139138

140-
expect(rules[0].inverted).to.be.true
139+
expect(rules[0].inverted).toBe(true)
141140
})
142141

143142
it('converts `inverted` to boolean, even it is not specified', () => {
144143
const rules = unpackRules([['read', 'Post,Comment']])
145144

146-
expect(rules[0].inverted).to.be.false
145+
expect(rules[0].inverted).toBe(false)
147146
})
148147

149148
it('puts 5th element under `fields` field and converts it to an array', () => {
150149
const fields = ['title', 'description']
151150
const rules = unpackRules([['read', 'Post,Comment', 1, 0, fields.join(',')]])
152151

153-
expect(rules[0].fields).to.deep.equal(fields)
152+
expect(rules[0].fields).toEqual(fields)
154153
})
155154

156155
it('converts `fields` to `undefined` if its value is `0`', () => {
157-
const rules = unpackRules([['read', 'Post,Comment', 1, 0, 0]])
156+
const rules = unpackRules([['read', 'Post,Comment', 1, 0, '']])
158157

159-
expect(rules[0].fields).to.be.undefined
158+
expect(rules[0].fields).toBe(undefined)
160159
})
161160

162161
it('puts 6th element under `reason` field', () => {
163162
const reason = 'forbidden reason'
164163
const rules = unpackRules([['read', 'Post,Comment', 1, 0, 0, reason]])
165164

166-
expect(rules[0].reason).to.equal(reason)
165+
expect(rules[0].reason).toBe(reason)
167166
})
168167

169168
it('converts `reason` to `undefined` if its value is `0`', () => {
170-
const rules = unpackRules([['read', 'Post,Comment', 1, 0, 0, 0]])
169+
const rules = unpackRules([['read', 'Post,Comment', 1, 0, 0, '']])
171170

172-
expect(rules[0].reason).to.be.undefined
171+
expect(rules[0].reason).toBe(undefined)
173172
})
174173
})
175174
})

packages/casl-ability/src/extra.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export function packRules<T extends RawRule<any, any>>(
151151
rule.reason || ''
152152
];
153153

154-
while (!packedRule[packedRule.length - 1]) packedRule.pop();
154+
while (packedRule.length > 0 && !packedRule[packedRule.length - 1]) packedRule.pop();
155155

156156
return packedRule;
157157
});
@@ -173,17 +173,9 @@ export function unpackRules<T extends RawRule<any, any>>(
173173
: subjects
174174
} as T;
175175

176-
if (conditions) {
177-
rule.conditions = conditions;
178-
}
179-
180-
if (fields) {
181-
rule.fields = fields.split(',');
182-
}
183-
184-
if (reason) {
185-
rule.reason = reason;
186-
}
176+
if (conditions) rule.conditions = conditions;
177+
if (fields) rule.fields = fields.split(',');
178+
if (reason) rule.reason = reason;
187179

188180
return rule;
189181
});

0 commit comments

Comments
 (0)