core/validators/nginx.validator.ts

core/validators/nginx.validator.ts is a file in Project Scripts. 138 lines of code and 24 definitions.

import {
    COMMENT_MARK,
    ENGINE_DIRECTIVE,
    ESCAPE,
    HEADER_DIRECTIVE,
    HEADER_FLAG,
    IMPORT_DIRECTIVE,
    POLICY_HEADER,
    PRIVATE_REFERRERS,
    QUOTES,
    REFERRER_HEADER,
    REFUSED_SOURCES,
    REQUIRED_ENGINE,
    TERMINATOR,
    TOKEN_BOUNDARIES,
    WILDCARD,
} from "#configuration/constants/nginx.constants";
import {
    COMMENT_REMEDY,
    ENGINE_MISSING,
    ENGINE_REMEDY,
    HEADERS_REMEDY,
    commentsHeading,
    commentsHeld,
    engineHeading,
    engineHeld,
    headersHeading,
    headersHeld,
    openReferrer,
    openSource,
    otherEngine,
} from "#configuration/strings/nginx.strings";
import type { CheckVerdict } from "#types/validation.types";
import type { ConfigFile } from "#types/nginx.types";

const NEWLINE = "\n";
const SPACE = " ";

const opensComment = function opensComment(line: string, at: number): boolean {
    return at === 0 || TOKEN_BOUNDARIES.has(line.charAt(at - 1));
};

const quoteAfter = function quoteAfter(quote: string, char: string): string {
    if (quote !== "") {
        return char === quote ? "" : quote;
    }
    return QUOTES.has(char) ? char : "";
};

const hasComment = function hasComment(line: string): boolean {
    let quote = "";
    for (let at = 0; at < line.length; at += 1) {
        const char = line.charAt(at);
        if (char === ESCAPE) {
            at += 1;
        } else if (quote === "" && char === COMMENT_MARK && opensComment(line, at)) {
            return true;
        } else {
            quote = quoteAfter(quote, char);
        }
    }
    return false;
};

export const commentVerdict = function commentVerdict(files: readonly ConfigFile[]): CheckVerdict {
    const found = files.flatMap((file) =>
        file.text
            .split(NEWLINE)
            .flatMap((line, index) => (hasComment(line) ? [`  ${file.path}:${String(index + 1)}`] : [])),
    );
    if (found.length === 0) {
        return { held: true, text: commentsHeld(files.length) };
    }
    return { held: false, text: [commentsHeading(found.length), ...found, COMMENT_REMEDY, ""].join(NEWLINE) };
};

const directivesOf = function directivesOf(text: string): readonly (readonly string[])[] {
    return text
        .split(NEWLINE)
        .map((line) => line.trim())
        .filter((line) => line.endsWith(TERMINATOR))
        .map((line) =>
            line
                .slice(0, -TERMINATOR.length)
                .split(SPACE)
                .filter((word) => word.length > 0),
        );
};

const engineFinding = function engineFinding(text: string): string | null {
    const directives = directivesOf(text);
    if (!directives.some((words) => words[0] === IMPORT_DIRECTIVE)) {
        return null;
    }
    const engines = directives.filter((words) => words[0] === ENGINE_DIRECTIVE).map((words) => words[1] ?? "");
    if (engines.length === 0) {
        return ENGINE_MISSING;
    }
    const other = engines.find((engine) => engine !== REQUIRED_ENGINE);
    return other === undefined ? null : otherEngine(other);
};

const headerValue = function headerValue(words: readonly string[]): string {
    const value = words.slice(2).filter((word) => word !== HEADER_FLAG);
    const text = value.join(SPACE);
    const quoted = text.length > 1 && QUOTES.has(text.charAt(0)) && text.endsWith(text.charAt(0));
    return quoted ? text.slice(1, -1) : text;
};

const sourceFindings = function sourceFindings(value: string): readonly string[] {
    return value
        .split(SPACE)
        .map((token) => (token.endsWith(TERMINATOR) ? token.slice(0, -TERMINATOR.length) : token))
        .filter((token) => REFUSED_SOURCES.has(token) || token.includes(WILDCARD))
        .map(openSource);
};

const headerFindings = function headerFindings(text: string): readonly string[] {
    return directivesOf(text)
        .filter((words) => words[0] === HEADER_DIRECTIVE)
        .flatMap((words) => {
            const value = headerValue(words);
            if (words[1] === POLICY_HEADER) {
                return sourceFindings(value);
            }
            if (words[1] === REFERRER_HEADER && !PRIVATE_REFERRERS.has(value)) {
                return [openReferrer(value)];
            }
            return [];
        });
};

export const headerVerdict = function headerVerdict(files: readonly ConfigFile[]): CheckVerdict {
    const found = files.flatMap((file) => headerFindings(file.text).map((finding) => `  ${file.path} ${finding}`));
    if (found.length === 0) {
        return { held: true, text: headersHeld(files.length) };
    }
    return { held: false, text: [headersHeading(found.length), ...found, HEADERS_REMEDY, ""].join(NEWLINE) };
};

export const engineVerdict = function engineVerdict(files: readonly ConfigFile[]): CheckVerdict {
    const found = files.flatMap((file) => {
        const finding = engineFinding(file.text);
        return finding === null ? [] : [`  ${file.path} ${finding}`];
    });
    if (found.length === 0) {
        return { held: true, text: engineHeld(files.length) };
    }
    return { held: false, text: [engineHeading(found.length), ...found, ENGINE_REMEDY, ""].join(NEWLINE) };
};