# core/adapters/security.adapter.ts

> 63 lines of code and 7 definitions.

Tree: Bane's Lab Build Scripts
Language: typescript
Layer: infrastructure
Canonical: https://banes-lab.com/anatomy/build-scripts#file-build-scripts-core-adapters-security-adapter-ts
Source text: https://banes-lab.com/source/build-scripts/core/adapters/security.adapter.ts.txt

Listed in [core/adapters](https://banes-lab.com/api/source/build-scripts/core/adapters.md), after [core/adapters/document.adapter.ts](https://banes-lab.com/source/build-scripts/core/adapters/document.adapter.ts.md) and before [core/adapters/server.adapter.ts](https://banes-lab.com/source/build-scripts/core/adapters/server.adapter.ts.md).

## Definitions

- `gpgArguments` (lexical_declaration, line 26)
- `importKey` (lexical_declaration, line 30)
- `gpgOutput` (lexical_declaration, line 38)
- `withHome` (lexical_declaration, line 16)
- `isSignedBy` (lexical_declaration, line 56, exported)
- `signText` (lexical_declaration, line 46, exported)
- `home` (lexical_declaration, line 17)

## Contained in

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

## Uses

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

## Used by

- [core/validators/security.validator.ts](https://banes-lab.com/source/build-scripts/core/validators/security.validator.ts.md)

## Linked from

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

## Source

```typescript
import {
    GPGCONF_BINARY,
    GPG_BINARY,
    OPENPGP_HOME_PREFIX,
    VAULT_KEY_ENCODING,
} from "#configuration/constants/security.constants";
import { mkdtempSync, rmSync } from "node:fs";
import { Buffer } from "node:buffer";
import type { SignedText } from "#types/site.types";
import { execFileSync } from "node:child_process";
import { isRecord } from "#core/selectors/base.selector";
import { join } from "node:path";
import { signingFailed } from "#configuration/strings/site.strings";
import { tmpdir } from "node:os";

const withHome = function withHome<T>(work: (home: string) => T): T {
    const home = mkdtempSync(join(tmpdir(), OPENPGP_HOME_PREFIX));
    try {
        return work(home);
    } finally {
        execFileSync(GPGCONF_BINARY, ["--homedir", home, "--kill", "all"], { stdio: "ignore" });
        rmSync(home, { force: true, recursive: true });
    }
};

const gpgArguments = function gpgArguments(home: string, args: readonly string[]): string[] {
    return ["--homedir", home, "--batch", "--quiet", ...args];
};

const importKey = function importKey(home: string, key: Buffer | string): void {
    try {
        execFileSync(GPG_BINARY, gpgArguments(home, ["--import"]), { input: key, stdio: ["pipe", "ignore", "pipe"] });
    } catch (error: unknown) {
        throw new Error(signingFailed("import"), { cause: error });
    }
};

const gpgOutput = function gpgOutput(home: string, step: string, args: readonly string[], input: string): string {
    try {
        return execFileSync(GPG_BINARY, gpgArguments(home, args), { encoding: "utf8", input, stdio: "pipe" });
    } catch (error: unknown) {
        throw new Error(signingFailed(step), { cause: error });
    }
};

export const signText = function signText(encodedKey: string, text: string): SignedText {
    return withHome((home) => {
        importKey(home, Buffer.from(encodedKey, VAULT_KEY_ENCODING));
        return {
            publicKey: gpgOutput(home, "export", ["--armor", "--export"], ""),
            signed: gpgOutput(home, "clearsign", ["--clearsign"], text),
        };
    });
};

export const isSignedBy = function isSignedBy(publicKey: string, signed: string): boolean {
    return withHome((home) => {
        importKey(home, publicKey);
        try {
            execFileSync(GPG_BINARY, gpgArguments(home, ["--verify"]), { input: signed, stdio: ["pipe", "ignore", "ignore"] });
            return true;
        } catch (error: unknown) {
            if (isRecord(error) && typeof error["status"] === "number") {
                return false;
            }
            throw new Error(signingFailed("verify"), { cause: error });
        }
    });
};
```
