Skip to content

Commit

Permalink
fix: allow non matching regex strings, if permitted by options
Browse files Browse the repository at this point in the history
  • Loading branch information
tada5hi committed Oct 28, 2022
1 parent 9bda36a commit 145b119
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 25 deletions.
48 changes: 25 additions & 23 deletions src/parameter/fields/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
FieldsInputTransformed, FieldsParseOptions, FieldsParseOutput,
} from './type';
import {
isValidFieldName,
parseFieldsInput, removeFieldInputOperator,
transformFieldsInput,
} from './utils';
Expand Down Expand Up @@ -94,26 +95,26 @@ export function parseQueryFields<T extends ObjectLiteral = ObjectLiteral>(
const output : FieldsParseOutput = [];

for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const path = keys[i];

if (
!isFieldPathAllowedByRelations({ path: key }, options.relations) &&
key !== DEFAULT_ID
!isFieldPathAllowedByRelations({ path }, options.relations) &&
path !== DEFAULT_ID
) {
continue;
}

let fields : string[] = [];

if (
hasOwnProperty(data, key)
hasOwnProperty(data, path)
) {
fields = parseFieldsInput(data[key]);
fields = parseFieldsInput(data[path]);
} else if (
hasOwnProperty(reverseMapping, key)
hasOwnProperty(reverseMapping, path)
) {
if (hasOwnProperty(data, reverseMapping[key])) {
fields = parseFieldsInput(data[reverseMapping[key]]);
if (hasOwnProperty(data, reverseMapping[path])) {
fields = parseFieldsInput(data[reverseMapping[path]]);
}
}

Expand All @@ -126,17 +127,18 @@ export function parseQueryFields<T extends ObjectLiteral = ObjectLiteral>(
if (fields.length > 0) {
for (let j = 0; j < fields.length; j++) {
fields[j] = applyMapping(
buildFieldWithPath({ name: fields[j], path: key }),
buildFieldWithPath({ name: fields[j], path }),
options.mapping,
true,
);
}

if (hasOwnProperty(domainFields, key)) {
fields = fields
.filter((field) => domainFields[key].indexOf(
removeFieldInputOperator(field),
) !== -1);
if (hasOwnProperty(domainFields, path)) {
fields = fields.filter((field) => domainFields[path].indexOf(
removeFieldInputOperator(field),
) !== -1);
} else {
fields = fields.filter((field) => isValidFieldName(removeFieldInputOperator(field)));
}

transformed = transformFieldsInput(
Expand All @@ -146,17 +148,17 @@ export function parseQueryFields<T extends ObjectLiteral = ObjectLiteral>(

if (
transformed.default.length === 0 &&
hasOwnProperty(defaultDomainFields, key)
hasOwnProperty(defaultDomainFields, path)
) {
transformed.default = defaultDomainFields[key];
transformed.default = defaultDomainFields[path];
}

if (
transformed.included.length === 0 &&
transformed.default.length === 0 &&
hasOwnProperty(allowedDomainFields, key)
hasOwnProperty(allowedDomainFields, path)
) {
transformed.default = allowedDomainFields[key];
transformed.default = allowedDomainFields[path];
}

transformed.default = Array.from(new Set([
Expand All @@ -173,16 +175,16 @@ export function parseQueryFields<T extends ObjectLiteral = ObjectLiteral>(

if (transformed.default.length > 0) {
for (let j = 0; j < transformed.default.length; j++) {
let path : string | undefined;
if (key !== DEFAULT_ID) {
path = key;
let destPath : string | undefined;
if (path !== DEFAULT_ID) {
destPath = path;
} else if (options.defaultPath) {
path = options.defaultPath;
destPath = options.defaultPath;
}

output.push({
key: transformed.default[j],
...(path ? { path } : {}),
...(destPath ? { path: destPath } : {}),
});
}
}
Expand Down
1 change: 1 addition & 0 deletions src/parameter/fields/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@

export * from './domain';
export * from './input';
export * from './name';
10 changes: 10 additions & 0 deletions src/parameter/fields/utils/name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

export function isValidFieldName(input: string) : boolean {
return /^[a-zA-Z_][a-zA-Z0-9_]*$/gu.test(input);
}
8 changes: 8 additions & 0 deletions src/parameter/filters/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
getFieldDetails,
hasOwnProperty, isFieldNonRelational, isFieldPathAllowedByRelations,
} from '../../utils';
import { isValidFieldName } from '../fields';
import { ParseAllowedOption } from '../type';
import { flattenParseAllowedOption, isPathCoveredByParseAllowedOption } from '../utils';
import { FilterComparisonOperator } from './constants';
Expand Down Expand Up @@ -164,6 +165,13 @@ export function parseQueryFilters<T extends ObjectLiteral = ObjectLiteral>(

const fieldDetails : FieldDetails = getFieldDetails(keys[i]);

if (
typeof options.allowed === 'undefined' &&
!isValidFieldName(fieldDetails.name)
) {
continue;
}

if (
!isFieldPathAllowedByRelations(fieldDetails, options.relations) &&
!isFieldNonRelational(fieldDetails)
Expand Down
4 changes: 3 additions & 1 deletion src/parameter/relations/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { applyMapping, hasOwnProperty } from '../../utils';
import { isPathCoveredByParseAllowedOption } from '../utils';

import { RelationsParseOptions, RelationsParseOutput } from './type';
import { includeParents } from './utils';
import { includeParents, isValidRelationPath } from './utils';

// --------------------------------------------------

Expand Down Expand Up @@ -64,6 +64,8 @@ export function parseQueryRelations<T extends ObjectLiteral = ObjectLiteral>(

if (options.allowed) {
items = items.filter((item) => isPathCoveredByParseAllowedOption(options.allowed, item));
} else {
items = items.filter((item) => isValidRelationPath(item));
}

if (options.includeParents) {
Expand Down
1 change: 1 addition & 0 deletions src/parameter/relations/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
*/

export * from './parents';
export * from './path';
10 changes: 10 additions & 0 deletions src/parameter/relations/utils/path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
* Copyright (c) 2022.
* Author Peter Placzek (tada5hi)
* For the full copyright and license information,
* view the LICENSE file that was distributed with this source code.
*/

export function isValidRelationPath(input: string) : boolean {
return /^[a-zA-Z0-9_-]+([.]*[a-zA-Z0-9_-])*$/gu.test(input);
}
9 changes: 9 additions & 0 deletions src/parameter/sort/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
hasOwnProperty, isFieldNonRelational,
isFieldPathAllowedByRelations,
} from '../../utils';
import { isValidFieldName } from '../fields';
import { ParseAllowedOption } from '../type';
import { flattenParseAllowedOption, isPathCoveredByParseAllowedOption } from '../utils';

Expand Down Expand Up @@ -146,6 +147,14 @@ export function parseQuerySort<T extends ObjectLiteral = ObjectLiteral>(
const key: string = applyMapping(parts[i], options.mapping);

const fieldDetails = getFieldDetails(key);

if (
typeof options.allowed === 'undefined' &&
!isValidFieldName(fieldDetails.name)
) {
continue;
}

if (
!isFieldPathAllowedByRelations(fieldDetails, options.relations) &&
!isFieldNonRelational(fieldDetails)
Expand Down
8 changes: 8 additions & 0 deletions test/unit/fields.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ describe('src/fields/index.ts', () => {
data = parseQueryFields(['id']);
expect(data).toEqual([{ key: 'id' }] as FieldsParseOutput);

// invalid field names
data = parseQueryFields(['"id', 'name!']);
expect(data).toEqual([] as FieldsParseOutput);

// ignore field name pattern, if permitted by allowed key
data = parseQueryFields(['name!'], { allowed: ['name!'] });
expect(data).toEqual([{key: 'name!'}] as FieldsParseOutput);

// empty allowed -> allows nothing
data = parseQueryFields(['id'], {allowed: []});
expect(data).toEqual([] as FieldsParseOutput);
Expand Down
12 changes: 12 additions & 0 deletions test/unit/filters.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ describe('src/filter/index.ts', () => {
operator: FilterComparisonOperator.EQUAL,
}] as FiltersParseOutput);

// invalid field name
allowedFilter = parseQueryFilters({ 'id!': 1 }, { allowed: undefined });
expect(allowedFilter).toEqual([] as FiltersParseOutput);

// ignore field name pattern, if permitted by allowed key
allowedFilter = parseQueryFilters({ 'id!': 1 }, { allowed: ['id!'] });
expect(allowedFilter).toEqual([{
key: 'id!',
value: 1,
operator: FilterComparisonOperator.EQUAL,
}] as FiltersParseOutput);

allowedFilter = parseQueryFilters({ name: 'tada5hi' }, { default: { name: 'admin' } });
expect(allowedFilter).toEqual([{
key: 'name',
Expand Down
10 changes: 10 additions & 0 deletions test/unit/relations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ describe('src/relations/index.ts', () => {
allowed = parseQueryRelations([], { allowed: ['profile'] });
expect(allowed).toEqual([]);

// invalid path
allowed = parseQueryRelations(['profile!']);
expect(allowed).toEqual([]);

// ignore path pattern, if permitted by allowed key
allowed = parseQueryRelations(['profile!'], {allowed: ['profile!']});
expect(allowed).toEqual([
{ key: 'profile!', value: 'profile!'}
] as RelationsParseOutput);

// with alias
allowed = parseQueryRelations('pro', { mapping: { pro: 'profile' }, allowed: ['profile'] });
expect(allowed).toEqual([
Expand Down
11 changes: 10 additions & 1 deletion test/unit/sort.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import {
SortParseOutput,
parseQueryRelations,
parseQuerySort,
FieldsParseOutput,
} from '../../src';
import {User} from "../data";

describe('src/sort/index.ts', () => {
it('should transform sort data', () => {
it('should parse sort data', () => {
// sort asc
let transformed = parseQuerySort('id', { allowed: ['id'] });
expect(transformed).toEqual([{ key: 'id', value: SortDirection.ASC }] as SortParseOutput);
Expand All @@ -24,6 +25,14 @@ describe('src/sort/index.ts', () => {
transformed = parseQuerySort('-id', { allowed: ['id'] });
expect(transformed).toEqual([{ key: 'id', value: SortDirection.DESC }] as SortParseOutput);

// invalid field names
transformed = parseQuerySort('-!id');
expect(transformed).toEqual([] as FieldsParseOutput);

// ignore field name pattern, if permitted by allowed key
transformed = parseQuerySort(['-!id'], { allowed: ['!id'] });
expect(transformed).toEqual([{key: '!id', value: SortDirection.DESC}] as FieldsParseOutput);

// empty allowed
transformed = parseQuerySort('-id', { allowed: [] });
expect(transformed).toEqual([] as SortParseOutput);
Expand Down

0 comments on commit 145b119

Please sign in to comment.