From 093eabae47860de213a485c71212afc4ea1aa54d Mon Sep 17 00:00:00 2001 From: Mradul Singh Date: Thu, 12 Nov 2026 18:51:50 +0530 Subject: [PATCH] fix: read keyGet2 values from the matched capture groups keyGet2 took the segment of key1 at the same split index as :pathVar in key2. That is wrong when /* spans more than one segment, and it gives "" when :pathVar is only part of a segment (/files/report-:id). Now it builds the regex like Go Casbin's KeyGet2 (/* -> /.*, :name -> ([^/]+)) and returns the capture group of :pathVar. Fixes #583 --- src/util/builtinOperators.ts | 28 +++++++++++++++------------- test/util.test.ts | 6 ++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/util/builtinOperators.ts b/src/util/builtinOperators.ts index 94e3414..03a0a71 100644 --- a/src/util/builtinOperators.ts +++ b/src/util/builtinOperators.ts @@ -108,21 +108,23 @@ function keyMatch2Func(...args: any[]): boolean { // For example, "/resource1" matches "/:resource" // if the pathVar == "resource", then "resource1" will be returned function keyGet2(key1: string, key2: string, pathVar: string): string { - if (keyMatch2(key1, key2)) { - const re = new RegExp('[^/]+', 'g'); - const keys = key2.match(re); - const values = key1.match(re); - if (!keys || !values) { - return ''; - } - const index = keys.indexOf(`:${pathVar}`); - if (index === -1) { - return ''; - } - return values[index]; - } else { + key2 = key2.replace(/\/\*/g, '/.*'); + if (key2 === '*') { + key2 = '.*'; + } + + const keys: string[] = key2.match(/:[^/]+/g) || []; + key2 = key2.replace(/:[^/]+/g, '([^/]+)'); + + const values = new RegExp('^' + key2 + '$').exec(key1); + if (!values) { + return ''; + } + const index = keys.indexOf(`:${pathVar}`); + if (index === -1) { return ''; } + return values[index + 1]; } function keyGet2Func(...args: any[]): string { diff --git a/test/util.test.ts b/test/util.test.ts index bce2f09..85bb91f 100644 --- a/test/util.test.ts +++ b/test/util.test.ts @@ -69,6 +69,12 @@ test('test keyGet2Func', () => { expect(util.keyGet2Func('/foo/baz/foo', '/foo/:bar/foo', 'bar')).toEqual('baz'); expect(util.keyGet2Func('/baz', '/foo', 'bar')).toEqual(''); expect(util.keyGet2Func('/foo/baz', '/foo', 'bar')).toEqual(''); + expect(util.keyGet2Func('/foo/baz', '*', 'bar')).toEqual(''); + expect(util.keyGet2Func('/orgs/acme/teams/t1/docs/42', '/orgs/*/docs/:id', 'id')).toEqual('42'); + expect(util.keyGet2Func('/a/b/c/d', '/*/:x/:y', 'x')).toEqual('c'); + expect(util.keyGet2Func('/a/b/c/d', '/*/:x/:y', 'y')).toEqual('d'); + expect(util.keyGet2Func('/files/report-7', '/files/report-:id', 'id')).toEqual('7'); + expect(util.keyGet2Func('/files/report-7', '/files/report-:id', 'other')).toEqual(''); }); test('test keyMatch3Func', () => {