logo

qbjs

API Reference

Security

API reference for security configuration and validation functions

The security module provides configuration types and validation functions to protect your API from malicious queries.

SecurityConfig

Configuration type for query validation.

interface SecurityConfig {
  allowedFields?: string[];
  allowedRelations?: string[];
  maxLimit?: number;
  operators?: FilterOperator[];
  defaultLimit?: number;
  defaultPage?: number;
}

Properties

PropertyTypeDefaultDescription
allowedFieldsstring[][]Fields allowed to be queried. Empty array means all fields allowed.
allowedRelationsstring[][]Relations allowed to be joined. Empty array means all relations allowed.
maxLimitnumber100Maximum limit for pagination. Queries exceeding this will be capped.
operatorsFilterOperator[]All operatorsFilter operators that are allowed.
defaultLimitnumber10Default limit when not specified in query.
defaultPagenumber1Default page when not specified in query.

Example

import { createQueryBuilder, createDrizzlePgCompiler } from '@qbjs/core';

const builder = createQueryBuilder({
  config: {
    allowedFields: ['id', 'name', 'email', 'createdAt'],
    maxLimit: 50,
    operators: ['eq', 'ne', 'contains', 'containsi', 'gt', 'lt', 'gte', 'lte'],
    defaultLimit: 20,
  },
  compiler: createDrizzlePgCompiler(),
});

DEFAULT_SECURITY_CONFIG

Default security configuration with sensible defaults.

const DEFAULT_SECURITY_CONFIG: ResolvedSecurityConfig = {
  allowedFields: [],      // Empty means all fields allowed
  allowedRelations: [],   // Empty means all relations allowed
  maxLimit: 100,
  operators: [...FILTER_OPERATORS], // All operators allowed
  defaultLimit: 10,
  defaultPage: 1,
};

resolveSecurityConfig

Merge user-provided security config with defaults.

import { resolveSecurityConfig } from '@qbjs/core';

const config = resolveSecurityConfig({
  allowedFields: ['id', 'name'],
  maxLimit: 50,
});

console.log(config.allowedFields);  // ['id', 'name']
console.log(config.maxLimit);       // 50
console.log(config.defaultLimit);   // 10 (from defaults)

Parameters

ParameterTypeRequiredDescription
configSecurityConfigNoUser-provided partial security config

Returns

Returns ResolvedSecurityConfig with all defaults applied.

Validation Functions

validateSecurity

Main entry point for security validation. Validates a QueryAST against security configuration.

import { validateSecurity } from '@qbjs/core';

const result = validateSecurity(ast, {
  allowedFields: ['id', 'name', 'email'],
  maxLimit: 50,
});

if (!result.valid) {
  console.log(result.errors);
}

// Use the potentially modified AST (e.g., with capped limit)
const validatedAst = result.ast;

Parameters

ParameterTypeRequiredDescription
astQueryAST | nullYesThe QueryAST to validate
configSecurityConfigNoSecurity configuration (uses defaults if not provided)

Returns

interface SecurityValidationResult {
  valid: boolean;
  errors: SecurityError[];
  warnings: SecurityWarning[];
  ast: QueryAST | null;
}

validateFields

Validate that requested fields are allowed by the security config.

import { validateFields } from '@qbjs/core';

const errors = validateFields(
  ['id', 'name', 'password'],  // requested fields
  ['id', 'name', 'email']      // allowed fields
);

// errors will contain an error for 'password'

Parameters

ParameterTypeRequiredDescription
fieldsstring[] | nullYesArray of field names to validate
allowedFieldsstring[]YesArray of allowed field names (empty means all allowed)

Returns

Returns SecurityError[] for disallowed fields.

validateLimit

Validate and cap the limit against maxLimit.

import { validateLimit } from '@qbjs/core';

const { limit, warning } = validateLimit(200, 100);

console.log(limit);    // 100 (capped)
console.log(warning);  // SecurityWarning about capping

Parameters

ParameterTypeRequiredDescription
limitnumberYesThe requested limit
maxLimitnumberYesThe maximum allowed limit

Returns

{ limit: number; warning: SecurityWarning | null }

validateOperators

Validate that filter operators are allowed by the security config.

import { validateOperators } from '@qbjs/core';

const errors = validateOperators(
  filterNode,
  ['eq', 'ne', 'contains']  // allowed operators
);

Parameters

ParameterTypeRequiredDescription
filterFilterNode | nullYesThe filter node to validate
allowedOperatorsFilterOperator[]YesArray of allowed operators
pathstring[]NoCurrent path for error reporting

Returns

Returns SecurityError[] for disallowed operators.

validateFilterFields

Validate filter fields against allowed fields.

import { validateFilterFields } from '@qbjs/core';

const errors = validateFilterFields(
  filterNode,
  ['id', 'name', 'email']  // allowed fields
);

Parameters

ParameterTypeRequiredDescription
filterFilterNode | nullYesThe filter node to validate
allowedFieldsstring[]YesArray of allowed field names (empty means all allowed)
pathstring[]NoCurrent path for error reporting

Returns

Returns SecurityError[] for disallowed fields.

validateSortFields

Validate sort fields against allowed fields.

import { validateSortFields } from '@qbjs/core';

const errors = validateSortFields(
  [{ field: 'createdAt', direction: 'desc' }],
  ['id', 'name', 'createdAt']  // allowed fields
);

Parameters

ParameterTypeRequiredDescription
sortSortSpec[]YesArray of sort specifications
allowedFieldsstring[]YesArray of allowed field names (empty means all allowed)

Returns

Returns SecurityError[] for disallowed fields.

extractFilterFields

Extract all field names referenced in a filter.

import { extractFilterFields } from '@qbjs/core';

const fields = extractFilterFields(filterNode);
// ['status', 'title', 'createdAt']

Parameters

ParameterTypeRequiredDescription
filterFilterNode | nullYesThe filter node to extract fields from

Returns

Returns string[] - array of unique field names.

Error Types

SecurityError

interface SecurityError {
  code: 'FIELD_NOT_ALLOWED' | 'OPERATOR_NOT_ALLOWED' | 'LIMIT_EXCEEDED';
  field: string;
  message: string;
  path: string[];
}

SecurityWarning

interface SecurityWarning {
  code: 'LIMIT_CAPPED';
  field: string;
  message: string;
  originalValue: number;
  cappedValue: number;
}

Complete Example

import { 
  parse, 
  validateSecurity,
  createQueryBuilder,
  createDrizzlePgCompiler 
} from '@qbjs/core';

// Option 1: Manual validation
const parseResult = parse({
  fields: 'id,name,password',
  filter: { status: { eq: 'active' } },
  limit: '200'
});

const securityResult = validateSecurity(parseResult.ast, {
  allowedFields: ['id', 'name', 'email', 'status'],
  maxLimit: 100,
  operators: ['eq', 'ne', 'contains']
});

if (!securityResult.valid) {
  console.log('Security errors:', securityResult.errors);
  // [{ code: 'FIELD_NOT_ALLOWED', field: 'password', ... }]
}

if (securityResult.warnings.length > 0) {
  console.log('Security warnings:', securityResult.warnings);
  // [{ code: 'LIMIT_CAPPED', originalValue: 200, cappedValue: 100, ... }]
}

// Option 2: Automatic validation via QueryBuilder
const builder = createQueryBuilder({
  config: {
    allowedFields: ['id', 'name', 'email', 'status'],
    maxLimit: 100,
    operators: ['eq', 'ne', 'contains']
  },
  compiler: createDrizzlePgCompiler()
});

// Security validation is applied automatically
const result = builder.parse({
  fields: 'id,name,password',
  filter: { status: { eq: 'active' } },
  limit: '200'
});

// result.errors will contain security errors
// result.warnings will contain security warnings

On this page