# core/validators/nginx.validator.ts

> 138 lines of code and 24 definitions.

Tree: Project Scripts
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/scripts#file-scripts-core-validators-nginx-validator-ts
Source text: https://banes-lab.com/source/scripts/core/validators/nginx.validator.ts.txt

Listed in [core/validators](https://banes-lab.com/api/source/scripts/core/validators.md), after [core/validators/dependency.validator.ts](https://banes-lab.com/source/scripts/core/validators/dependency.validator.ts.md) and before [core/validators/server.validator.ts](https://banes-lab.com/source/scripts/core/validators/server.validator.ts.md).

## Definitions

- `opensComment` (lexical_declaration, line 39)
- `quoteAfter` (lexical_declaration, line 43)
- `directivesOf` (lexical_declaration, line 77)
- `sourceFindings` (lexical_declaration, line 110)
- `headerFindings` (lexical_declaration, line 118)
- `hasComment` (lexical_declaration, line 50)
- `commentVerdict` (lexical_declaration, line 65, exported)
- `headerVerdict` (lexical_declaration, line 133, exported)
- `engineVerdict` (lexical_declaration, line 141, exported)
- `engineFinding` (lexical_declaration, line 90)
- `NEWLINE` (lexical_declaration, line 36)
- `SPACE` (lexical_declaration, line 37)
- `quote` (lexical_declaration, line 51)
- `at` (lexical_declaration, line 52)
- `char` (lexical_declaration, line 53)
- `directives` (lexical_declaration, line 91)
- `engines` (lexical_declaration, line 95)
- `other` (lexical_declaration, line 99)
- `headerValue` (lexical_declaration, line 103)
- `text` (lexical_declaration, line 105)
- `quoted` (lexical_declaration, line 106)
- `value` (lexical_declaration, line 122)
- `found` (lexical_declaration, line 142, exported)
- `finding` (lexical_declaration, line 143, exported)

## Contained in

- [core/validators](https://banes-lab.com/anatomy/scripts/folder-scripts-core-validators.md)

## Uses

- [configuration/strings/nginx.strings.ts](https://banes-lab.com/source/scripts/configuration/strings/nginx.strings.ts.md)

## Linked from

- [configuration/strings](https://banes-lab.com/anatomy/scripts/folder-scripts-configuration-strings.md)
- [core/validators](https://banes-lab.com/anatomy/scripts/folder-scripts-core-validators.md)

## Source

```typescript
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) };
};
```
