diff --git a/src/scimPatch.ts b/src/scimPatch.ts index d91290fb..fb6aa78b 100644 --- a/src/scimPatch.ts +++ b/src/scimPatch.ts @@ -63,6 +63,8 @@ const IS_ARRAY_SEARCH = /(\[|\])/; const ARRAY_SEARCH = /^(.+)\[(.+)\]$/; // Split path on periods const SPLIT_PERIOD = /(?!\B"[^[]*)\.(?![^\]]*"\B)/g; +// Regex to fetch the URN from a path. +const URN_MATCH = /^((?:[A-Za-z0-9][A-Za-z0-9.+-]*:)+[A-Za-z0-9.+-]*)/; // Valid patch operation, value needs to be in lowercase here. const AUTHORIZED_OPERATION = ['remove', 'add', 'replace']; @@ -144,7 +146,10 @@ function validatePatchOperation(operation: ScimPatchOperation): void { } function resolvePaths(path: string): string[] { - const uriIndex = path.lastIndexOf(':'); + // Identify the URN prefix if present + const urnPath = path.match(URN_MATCH); + // Find the last colon in the urn path + const uriIndex = urnPath ? urnPath[1].lastIndexOf(':') : -1; if (uriIndex < 0) { // No schema prefix - this is a core schema path diff --git a/test/scimPatch.test.ts b/test/scimPatch.test.ts index 3dc01860..4205c168 100644 --- a/test/scimPatch.test.ts +++ b/test/scimPatch.test.ts @@ -1195,6 +1195,23 @@ describe('SCIM PATCH', () => { expect(afterPatch.emails[3].newProperty).to.be.an('undefined'); return done(); }); + + it('REPLACE: should handle colon in quoted filter values', done => { + scimUser.roles = [ + { value: "3675b69e-8324-4110-bdca-059031aa8da3:admin", type: "admin" }, + { value: "other-role", type: "user" } + ]; + const expected = "updated"; + const patch: ScimPatchAddReplaceOperation = { + op: 'replace', + value: expected, + path: 'roles[value eq "3675b69e-8324-4110-bdca-059031aa8da3:admin"].value' + }; + const afterPatch = scimPatch(scimUser, [patch]); + expect(afterPatch.roles![0].value).to.be.eq(expected); + expect(afterPatch.roles![1].value).to.be.eq("other-role"); + return done(); + }); }); describe('invalid requests', () => {