redos-detector
Version:
A CLI and library which tests helps score how vulnerable a regex pattern is to ReDoS attacks. Supported in the browser, Node and Deno.
227 lines (226 loc) • 7.63 kB
TypeScript
export { downgradePattern, DowngradePatternConfig } from './downgrade-pattern';
export * from './to-friendly';
/**
* The current version.
*/
export declare const version: string;
export type RedosDetectorNodeLocation = {
/**
* The first character in the pattern has offset `0`.
*/
readonly offset: number;
};
export type RedosDetectorNode = {
/**
* The end location of the node (exclusive).
*/
readonly end: RedosDetectorNodeLocation;
/**
* The contents of the node.
*/
readonly source: string;
/**
* The start location of the node (inclusive).
*/
readonly start: RedosDetectorNodeLocation;
};
export type RedosDetectorBackReference = {
/**
* The index of the capturing group the backreference points at.
* The first group has index `1`.
*/
readonly index: number;
/**
* The back refernce node.
*/
readonly node: RedosDetectorNode;
};
export type RedosDetectorBackReferenceStack = readonly RedosDetectorBackReference[];
export type RedosDetectorQuantifierIteration = {
/**
* The iteration number. The first iteration is `0`.
*/
readonly iteration: number;
/**
* The quantifier node.
*/
readonly node: RedosDetectorNode;
};
export type RedosDetectorQuantifierIterations = readonly RedosDetectorQuantifierIteration[];
export type RedosDetectorTrailEntrySide = {
/**
* If not `null`, this means the current node is part of the backreference.
*/
readonly backreferenceStack: RedosDetectorBackReferenceStack;
/**
* The node.
*/
readonly node: RedosDetectorNode;
/**
* The iteration of each quantifier the current node is part of.
*/
readonly quantifierIterations: RedosDetectorQuantifierIterations;
};
export type RedosDetectorTrailEntry = {
readonly a: RedosDetectorTrailEntrySide;
readonly b: RedosDetectorTrailEntrySide;
};
export type RedosDetectorTrail = {
/**
* A trail.
*/
readonly trail: readonly RedosDetectorTrailEntry[];
};
export type IsSafeConfig = {
/**
* If worst case count of possible backtracks is above this number,
* the regex will be considered unsafe.
*/
readonly maxScore?: number;
/**
* The maximum number of steps to make. If this limit is hit `error`
* will be `hitMaxSteps`.
*
* Note it's possible for there to be a infinite number of results,
* and therefore an inifinite number of steps.
*/
readonly maxSteps?: number;
/**
* The maximum amount of time (ms) to spend processing. Once this time
* is passed the trails found so far will be returned, and the `error`
* will be `timeout`.
*
* Note it's possible for there to be a infinite number of results.
*/
readonly timeout?: number;
} & ({
/**
* The offsets of groups which should be considered atomic.
* This is an advanced option you probably never want to use.
*
* It exists because sometimes when a pattern is downgraded, some of
* the groups in the downgrade can be considered atomic.
*/
readonly atomicGroupOffsets?: ReadonlySet<number>;
/**
* Do not downgrade the pattern if it's not supported as is.
*
* An exception may be thrown if the pattern needed to be downgraded.
*/
readonly downgradePattern: false;
} | {
readonly atomicGroupOffsets?: undefined;
/**
* Automatically downgrade the pattern if it's not supported as is.
*
* If this happens `patternDowngraded` will be `true` and `pattern`
* will contain the downgraded version.
*
* You can downgrade the pattern yourself with `downgradePattern`.
*/
readonly downgradePattern?: true;
});
export type RedosDetectorError = 'hitMaxScore' | 'hitMaxSteps' | 'timedOut';
export type Score = {
infinite: false;
value: number;
} | {
infinite: true;
};
export type RedosDetectorResult = {
/**
* The pattern that was checked. If it was downgraded this will be
* the downgraded version.
*/
readonly pattern: string;
/**
* `true` if the pattern needed to be downgraded.
*/
readonly patternDowngraded: boolean;
/**
* An array of trails. Each trail shows 2 different ways through the pattern
* side by side.
*
* For every trail there's an input string that could
* match the regex multiple ways if backtracking occurred.
*/
readonly trails: RedosDetectorTrail[];
/**
* The score.
*
* How is this calculated?
* - All the different paths an input string could take through the provided pattern are calculated.
* - Then for each candidate path found above, starting from just the first character, up to the complete path,
* all the other paths that could also match a string that matches the candidate path are found.
* - The score is the highest number found above. The higher the score, the more backtracks an engine will
* potentially need to take if the input string doesn't match the pattern.
* - If the score is `1` this means no backtracks can occur and for every possible input string the pattern
* could only match one way.
* - If there are too many different paths it can be too expensive to calculate an accurate score,
* so it falls back incrementing every time a new path is found.
*
* If it's infinite the `infinite` property will be `true`, otherwise the number
* will be on `value`.
*/
readonly score: Score;
} & ({
/**
* `null` means no error occurred.
*/
readonly error: null;
/**
* `true` means the regex pattern is not susceptible to ReDoS attacks
* based on the configured `maxScore` option.
*/
readonly safe: true;
} | {
/**
* The error that occurred.
*
* `trails` will still contain the trails that were found before
* the error occurred.
*/
readonly error: RedosDetectorError;
/**
* `false` means the regex pattern is susceptible to ReDoS attacks.
*/
readonly safe: false;
});
export type IsSafePatternConfig = IsSafeConfig & {
/**
* Enable case insensitive mode.
*/
readonly caseInsensitive?: boolean;
/**
* Enable dot-all mode, which allows `.` to match new lines.
*/
readonly dotAll?: boolean;
/**
* Enable multi-line mode which changes `^` and `$` to
* match the start or end of any line within the string.
*/
readonly multiLine?: boolean;
/**
* Enable unicode mode.
*/
readonly unicode?: boolean;
};
export declare const defaultTimeout: number;
export declare const defaultMaxScore = 200;
export declare const defaultMaxSteps = 20000;
export declare const defaultMultiLine = false;
export declare const defaultUnicode = false;
export declare const defaultCaseInsensitive = false;
export declare const defaultDotAll = false;
/**
* Check if the provided input pattern is not susceptible to ReDoS attacks.
*
* Can be configured with various options in the second argument.
*/
export declare function isSafePattern(inputPattern: string, { atomicGroupOffsets: atomicGroupOffsetsInput, maxScore, maxSteps, multiLine, timeout, caseInsensitive, dotAll, unicode, downgradePattern, }?: IsSafePatternConfig): RedosDetectorResult;
/**
* Check if the provided regular expression object is not susceptible to ReDoS attacks.
*
* Can be configured with various options in the second argument.
*/
export declare function isSafe(regexp: RegExp, config?: IsSafeConfig): RedosDetectorResult;