Skip to content

Commit 8ad4366

Browse files
committed
chore: addressing next batch of comments
1 parent 653b69c commit 8ad4366

File tree

3 files changed

+59
-26
lines changed

3 files changed

+59
-26
lines changed

pkg/java/src/main/java/dev/openfga/language/validation/ValidationOptions.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
public class ValidationOptions {
44

5-
private static final String DEFAULT_TYPE_PATTERN = "^[^:#@\\s]{1,254}$";
6-
private static final String DEFAULT_RELATION_PATTERN = "^[^:#@\\s]{1,50}$";
5+
private static final String DEFAULT_TYPE_PATTERN = "^[^:#@\\*\\s]{1,254}$";
6+
private static final String DEFAULT_RELATION_PATTERN = "^[^:#@\\*\\s]{1,50}$";
77

88
private String typePattern = DEFAULT_TYPE_PATTERN;
99
private String relationPattern = DEFAULT_RELATION_PATTERN;

pkg/js/validator/validate-rules.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ export const Rules = {
22
type: "[^:#@\\*\\s]{1,254}",
33
relation: "[^:#@\\*\\s]{1,50}",
44
condition: "[^\\*\\s]{2,256}",
5-
object: "[^\\s]{2,256}",
65
id: "[^#:\\*\\s]+",
6+
object: "[^\\s]{2,256}",
77
};
88

99
export const Validate = {
1010
// An Object is composed of a type and identifier (e.g. 'document:1')
1111
object: (object: string): boolean => {
12-
return validateFieldValue(`^${Rules.type}:${Rules.id}$`, object);
12+
return validateFieldValue(`^${Rules.type}:${Rules.id}$`, object) && validateFieldValue(`^${Rules.object}$`, object);
1313
},
1414
// Relation reference
1515
relation: (relation: string): boolean => {
@@ -21,7 +21,10 @@ export const Validate = {
2121
},
2222
// User is composed of type and identifier (e.g. 'group:engineering')
2323
userObject: (userObject: string): boolean => {
24-
return validateFieldValue(`^${Rules.type}:${Rules.id}$`, userObject);
24+
return (
25+
validateFieldValue(`^${Rules.type}:${Rules.id}$`, userObject) &&
26+
validateFieldValue(`^${Rules.object}$`, userObject)
27+
);
2528
},
2629
// User is composed of type, and a wildcard (e.g. 'group:*')
2730
userWildcard: (userWildcard: string): boolean => {

pkg/js/validator/validate-store.ts

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -164,23 +164,49 @@ function mapTuple(tuple: TupleKey): RelationReference {
164164
};
165165
}
166166

167+
function parseObjectString(object: string): { type: string; id: string } {
168+
const result = object.split(":");
169+
return { type: result[0], id: result[1] };
170+
}
171+
172+
function parseUserString(user: string): {
173+
type: string;
174+
id: string | undefined;
175+
relation: string | undefined;
176+
wildcard: boolean;
177+
} {
178+
const result = user.split(":");
179+
const type = result[0];
180+
181+
if (result[1] === "*") {
182+
return { type, id: undefined, relation: undefined, wildcard: true };
183+
}
184+
185+
if (result[1].includes("#")) {
186+
const [id, relation] = result[1].split("#");
187+
return { type, id, relation, wildcard: false };
188+
}
189+
190+
return { type, id: result[1], relation: undefined, wildcard: false };
191+
}
192+
167193
// Validation for Types
168194

169195
function validateTypes(tuple: TupleKey, types: string[], instancePath: string): boolean {
170196
const errors = [];
171197

172-
const user = tuple.user.split(":")[0];
198+
const userType = parseUserString(tuple.user).type;
173199

174200
// Ensure valid type of user
175-
if (!types.includes(user)) {
176-
errors.push(invalidType(user, types, instancePath + "/user"));
201+
if (!types.includes(userType)) {
202+
errors.push(invalidType(userType, types, instancePath + "/user"));
177203
}
178204

179-
const object = tuple.object.split(":")[0];
205+
const objectType = parseObjectString(tuple.object).type;
180206

181207
// Ensure valid type of object
182-
if (!types.includes(object)) {
183-
errors.push(invalidType(object, types, instancePath + "/object"));
208+
if (!types.includes(objectType)) {
209+
errors.push(invalidType(objectType, types, instancePath + "/object"));
184210
}
185211

186212
// Report all errors
@@ -198,22 +224,26 @@ function validateRelation(tuple: TupleKey, typeDefs: TypeDefinition[], instanceP
198224
// Check if relation exists on given type
199225
let doesExistOnType = false;
200226
if (tuple.user.includes("#")) {
201-
const user = tuple.user.split(":")[0];
202-
const userRelation = tuple.user.split("#")[1];
227+
const userResult = parseUserString(tuple.user);
203228
for (const typeDef of typeDefs) {
204-
if (typeDef && typeDef.type === user && typeDef.relations?.[userRelation]) {
229+
if (
230+
typeDef &&
231+
typeDef.type === userResult.type &&
232+
userResult.relation &&
233+
typeDef.relations?.[userResult.relation]
234+
) {
205235
doesExistOnType = true;
206236
break;
207237
}
208238
}
209239

210-
if (!doesExistOnType) {
211-
errors.push(relationMustExistOnType(userRelation, user, instancePath + "/user"));
240+
if (!doesExistOnType && userResult.relation) {
241+
errors.push(relationMustExistOnType(userResult.relation, userResult.type, instancePath + "/user"));
212242
}
213243
}
214244

215245
// Check if relation exists on given object
216-
const objectType = tuple.object.split(":")[0];
246+
const objectType = parseObjectString(tuple.object).type;
217247
let doesExistOnObject = false;
218248
for (const typeDef of typeDefs) {
219249
if (typeDef && typeDef.type === objectType && typeDef.relations?.[tuple.relation]) {
@@ -256,7 +286,7 @@ function validateTypeRestrictions(
256286
validateTuple.errors = validateTuple.errors || [];
257287

258288
const mappedTuple = mapTuple(tuple);
259-
const type = tuple.object.split(":")[0];
289+
const type = parseObjectString(tuple.object).type;
260290
const foundType = typeDefs.filter((t) => t.type === type)[0];
261291
const userTypes = foundType?.metadata?.relations?.[tuple.relation].directly_related_user_types;
262292

@@ -349,7 +379,7 @@ const validateTuple: SchemaValidateFunction = function (
349379
// Validate the type field for check and list_objects
350380
function validateUserField(model: AuthorizationModel, types: string[], userField: string, instancePath: string) {
351381
const errors = [];
352-
const foundType = userField.split(":")[0];
382+
const foundType = parseUserString(userField).type;
353383

354384
// Ensure valid type
355385
if (!types.includes(foundType)) {
@@ -434,11 +464,11 @@ function validateCheck(
434464

435465
if (checkTest.object && isStringValue(checkTest.object)) {
436466
const checkObject = checkTest.object;
437-
const object = checkObject.split(":")[0];
467+
const objectType = parseObjectString(checkObject).type;
438468

439469
// Ensure valid type of object
440-
if (!types.includes(object)) {
441-
objectErrors.push(invalidTypeUser(object, types, instancePath + "/object"));
470+
if (!types.includes(objectType)) {
471+
objectErrors.push(invalidTypeUser(objectType, types, instancePath + "/object"));
442472
}
443473

444474
if (!objectErrors.length) {
@@ -447,7 +477,7 @@ function validateCheck(
447477
}
448478
}
449479

450-
objectErrors.push(...validateAssertionField(model, object, checkTest.assertions, instancePath));
480+
objectErrors.push(...validateAssertionField(model, objectType, checkTest.assertions, instancePath));
451481
}
452482

453483
const context = checkTest.context;
@@ -520,11 +550,11 @@ function validateListUsers(
520550
if (listUsers && isStringValue(listUsers.object)) {
521551
const listUserObj = listUsers.object;
522552

523-
const object = listUserObj.split(":")[0];
553+
const objectType = parseObjectString(listUserObj).type;
524554

525555
// Ensure valid type of object
526-
if (!types.includes(object)) {
527-
errors.push(invalidTypeUser(object, types, instancePath + "/object"));
556+
if (!types.includes(objectType)) {
557+
errors.push(invalidTypeUser(objectType, types, instancePath + "/object"));
528558
}
529559

530560
if (!errors.length) {

0 commit comments

Comments
 (0)