diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 00000000..2bad7903
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,6 @@
+{
+ "extends": ["next/core-web-vitals"],
+ "rules": {
+ "@next/next/no-img-element": "off"
+ }
+}
diff --git a/.gitignore b/.gitignore
index fbb8167e..772f5c21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,8 @@
-.DS_Store
-.idea
-._*
-.vscode
-certbot-help.txt
-test/node_modules
-*/node_modules
-docker/dev/dnsrouter-config.json.tmp
-docker/dev/resolv.conf
+node_modules
+.next
+out
+dist
+data
+*.log
+.env*
+/.idea
diff --git a/Jenkinsfile b/Jenkinsfile
deleted file mode 100644
index af913c2e..00000000
--- a/Jenkinsfile
+++ /dev/null
@@ -1,285 +0,0 @@
-import groovy.transform.Field
-
-@Field
-def shOutput = ""
-def buildxPushTags = ""
-
-pipeline {
- agent {
- label 'docker-multiarch'
- }
- options {
- buildDiscarder(logRotator(numToKeepStr: '5'))
- disableConcurrentBuilds()
- ansiColor('xterm')
- }
- environment {
- IMAGE = 'nginx-proxy-manager'
- BUILD_VERSION = getVersion()
- MAJOR_VERSION = '2'
- BRANCH_LOWER = "${BRANCH_NAME.toLowerCase().replaceAll('\\\\', '-').replaceAll('/', '-').replaceAll('\\.', '-')}"
- BUILDX_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}"
- COMPOSE_INTERACTIVE_NO_CLI = 1
- }
- stages {
- stage('Environment') {
- parallel {
- stage('Master') {
- when {
- branch 'master'
- }
- steps {
- script {
- buildxPushTags = "-t docker.io/jc21/${IMAGE}:${BUILD_VERSION} -t docker.io/jc21/${IMAGE}:${MAJOR_VERSION} -t docker.io/jc21/${IMAGE}:latest"
- }
- }
- }
- stage('Other') {
- when {
- not {
- branch 'master'
- }
- }
- steps {
- script {
- // Defaults to the Branch name, which is applies to all branches AND pr's
- buildxPushTags = "-t docker.io/nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}"
- }
- }
- }
- stage('Versions') {
- steps {
- sh 'cat frontend/package.json | jq --arg BUILD_VERSION "${BUILD_VERSION}" \'.version = $BUILD_VERSION\' | sponge frontend/package.json'
- sh 'echo -e "\\E[1;36mFrontend Version is:\\E[1;33m $(cat frontend/package.json | jq -r .version)\\E[0m"'
- sh 'cat backend/package.json | jq --arg BUILD_VERSION "${BUILD_VERSION}" \'.version = $BUILD_VERSION\' | sponge backend/package.json'
- sh 'echo -e "\\E[1;36mBackend Version is:\\E[1;33m $(cat backend/package.json | jq -r .version)\\E[0m"'
- sh 'sed -i -E "s/(version-)[0-9]+\\.[0-9]+\\.[0-9]+(-green)/\\1${BUILD_VERSION}\\2/" README.md'
- }
- }
- stage('Docker Login') {
- steps {
- withCredentials([usernamePassword(credentialsId: 'jc21-dockerhub', passwordVariable: 'dpass', usernameVariable: 'duser')]) {
- sh 'docker login -u "${duser}" -p "${dpass}"'
- }
- }
- }
- }
- }
- stage('Builds') {
- parallel {
- stage('Project') {
- steps {
- script {
- // Frontend and Backend
- def shStatusCode = sh(label: 'Checking and Building', returnStatus: true, script: '''
- set -e
- ./scripts/ci/frontend-build > ${WORKSPACE}/tmp-sh-build 2>&1
- ./scripts/ci/test-and-build > ${WORKSPACE}/tmp-sh-build 2>&1
- ''')
- shOutput = readFile "${env.WORKSPACE}/tmp-sh-build"
- if (shStatusCode != 0) {
- error "${shOutput}"
- }
- }
- }
- post {
- always {
- sh 'rm -f ${WORKSPACE}/tmp-sh-build'
- }
- failure {
- npmGithubPrComment("CI Error:\n\n```\n${shOutput}\n```", true)
- }
- }
- }
- stage('Docs') {
- steps {
- dir(path: 'docs') {
- sh 'yarn install'
- sh 'yarn build'
- }
- }
- }
- }
- }
- stage('Test Sqlite') {
- environment {
- COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}_sqlite"
- COMPOSE_FILE = 'docker/docker-compose.ci.yml:docker/docker-compose.ci.sqlite.yml'
- }
- when {
- not {
- equals expected: 'UNSTABLE', actual: currentBuild.result
- }
- }
- steps {
- sh 'rm -rf ./test/results/junit/*'
- sh './scripts/ci/fulltest-cypress'
- }
- post {
- always {
- // Dumps to analyze later
- sh 'mkdir -p debug/sqlite'
- sh 'docker logs $(docker-compose ps --all -q fullstack) > debug/sqlite/docker_fullstack.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q stepca) > debug/sqlite/docker_stepca.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q pdns) > debug/sqlite/docker_pdns.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/sqlite/docker_pdns-db.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/sqlite/docker_dnsrouter.log 2>&1'
- junit 'test/results/junit/*'
- sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
- }
- unstable {
- dir(path: 'test/results') {
- archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
- }
- }
- }
- }
- stage('Test Mysql') {
- environment {
- COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}_mysql"
- COMPOSE_FILE = 'docker/docker-compose.ci.yml:docker/docker-compose.ci.mysql.yml'
- }
- when {
- not {
- equals expected: 'UNSTABLE', actual: currentBuild.result
- }
- }
- steps {
- sh 'rm -rf ./test/results/junit/*'
- sh './scripts/ci/fulltest-cypress'
- }
- post {
- always {
- // Dumps to analyze later
- sh 'mkdir -p debug/mysql'
- sh 'docker logs $(docker-compose ps --all -q fullstack) > debug/mysql/docker_fullstack.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q stepca) > debug/mysql/docker_stepca.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q pdns) > debug/mysql/docker_pdns.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/mysql/docker_pdns-db.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/mysql/docker_dnsrouter.log 2>&1'
- junit 'test/results/junit/*'
- sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
- }
- unstable {
- dir(path: 'test/results') {
- archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
- }
- }
- }
- }
- stage('Test Postgres') {
- environment {
- COMPOSE_PROJECT_NAME = "npm_${BRANCH_LOWER}_${BUILD_NUMBER}_postgres"
- COMPOSE_FILE = 'docker/docker-compose.ci.yml:docker/docker-compose.ci.postgres.yml'
- }
- when {
- not {
- equals expected: 'UNSTABLE', actual: currentBuild.result
- }
- }
- steps {
- sh 'rm -rf ./test/results/junit/*'
- sh './scripts/ci/fulltest-cypress'
- }
- post {
- always {
- // Dumps to analyze later
- sh 'mkdir -p debug/postgres'
- sh 'docker logs $(docker-compose ps --all -q fullstack) > debug/postgres/docker_fullstack.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q stepca) > debug/postgres/docker_stepca.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q pdns) > debug/postgres/docker_pdns.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/postgres/docker_pdns-db.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/postgres/docker_dnsrouter.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q db-postgres) > debug/postgres/docker_db-postgres.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q authentik) > debug/postgres/docker_authentik.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q authentik-redis) > debug/postgres/docker_authentik-redis.log 2>&1'
- sh 'docker logs $(docker-compose ps --all -q authentik-ldap) > debug/postgres/docker_authentik-ldap.log 2>&1'
-
- junit 'test/results/junit/*'
- sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
- }
- unstable {
- dir(path: 'test/results') {
- archiveArtifacts(allowEmptyArchive: true, artifacts: '**/*', excludes: '**/*.xml')
- }
- }
- }
- }
- stage('MultiArch Build') {
- when {
- not {
- equals expected: 'UNSTABLE', actual: currentBuild.result
- }
- }
- steps {
- sh "./scripts/buildx --push ${buildxPushTags}"
- }
- }
- stage('Docs / Comment') {
- parallel {
- stage('Docs Job') {
- when {
- allOf {
- branch pattern: "^(develop|master)\$", comparator: "REGEXP"
- not {
- equals expected: 'UNSTABLE', actual: currentBuild.result
- }
- }
- }
- steps {
- build wait: false, job: 'nginx-proxy-manager-docs', parameters: [string(name: 'docs_branch', value: "$BRANCH_NAME")]
- }
- }
- stage('PR Comment') {
- when {
- allOf {
- changeRequest()
- not {
- equals expected: 'UNSTABLE', actual: currentBuild.result
- }
- }
- }
- steps {
- script {
- npmGithubPrComment("""Docker Image for build ${BUILD_NUMBER} is available on [DockerHub](https://cloud.docker.com/repository/docker/nginxproxymanager/${IMAGE}-dev):
-```
-nginxproxymanager/${IMAGE}-dev:${BRANCH_LOWER}
-```
-
-> [!NOTE]
-> Ensure you backup your NPM instance before testing this image! Especially if there are database changes.
-> This is a different docker image namespace than the official image.
-
-> [!WARNING]
-> Changes and additions to DNS Providers require verification by at least 2 members of the community!
-""", true)
- }
- }
- }
- }
- }
- }
- post {
- always {
- sh 'echo Reverting ownership'
- sh 'docker run --rm -v "$(pwd):/data" jc21/ci-tools chown -R "$(id -u):$(id -g)" /data'
- printResult(true)
- }
- failure {
- archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
- }
- unstable {
- archiveArtifacts(artifacts: 'debug/**/*.*', allowEmptyArchive: true)
- }
- }
-}
-
-def getVersion() {
- ver = sh(script: 'cat .version', returnStdout: true)
- return ver.trim()
-}
-
-def getCommit() {
- ver = sh(script: 'git log -n 1 --format=%h', returnStdout: true)
- return ver.trim()
-}
diff --git a/README.md b/README.md
index 2116a55a..657c5b7c 100644
--- a/README.md
+++ b/README.md
@@ -1,120 +1,114 @@
-
-
-
-
-
-
-
-
-
-
-
+# Caddy Proxy Manager
-This project comes as a pre-built docker image that enables you to easily forward to your websites
-running at home or otherwise, including free SSL, without having to know too much about Nginx or Letsencrypt.
+Caddy Proxy Manager is a modern control panel for Caddy that simplifies reverse proxy configuration, TLS automation, access control, and observability. The entire application is built with Next.js and ships with a lean dependency set, OAuth2 login, and a battery of tools for managing hosts, redirects, streams, certificates, and Cloudflare DNS-based certificate issuance.
-- [Quick Setup](#quick-setup)
-- [Full Setup](https://nginxproxymanager.com/setup/)
-- [Screenshots](https://nginxproxymanager.com/screenshots/)
+## Highlights
-## Project Goal
+- **Next.js 14 App Router** UI and API in a single project, backed by an embedded SQLite database.
+- **OAuth2 single sign-on** with PKCE and configurable claim mapping. The first authenticated user becomes the administrator.
+- **End-to-end Caddy orchestration** using the admin API, generating JSON configurations for HTTP, HTTPS, redirects, custom 404 hosts, and TCP/UDP streams.
+- **Cloudflare DNS challenge integration** via xcaddy-built Caddy binary with `cloudflare` and `layer4` modules; credentials are stored in the UI.
+- **Access lists** (HTTP basic auth), custom certificates (managed or imported PEM), and a full audit log of administrative changes.
+- **Default HSTS configuration** (`Strict-Transport-Security: max-age=63072000`) baked into every HTTP route to meet security baseline requirements.
-I created this project to fill a personal need to provide users with an easy way to accomplish reverse
-proxying hosts with SSL termination and it had to be so easy that a monkey could do it. This goal hasn't changed.
-While there might be advanced options they are optional and the project should be as simple as possible
-so that the barrier for entry here is low.
+## Project Structure
-
-
-
-## Features
-
-- Beautiful and Secure Admin Interface based on [Tabler](https://tabler.github.io/)
-- Easily create forwarding domains, redirections, streams and 404 hosts without knowing anything about Nginx
-- Free SSL using Let's Encrypt or provide your own custom SSL certificates
-- Access Lists and basic HTTP Authentication for your hosts
-- Advanced Nginx configuration available for super users
-- User management, permissions and audit log
-
-
-## Hosting your home network
-
-I won't go in to too much detail here but here are the basics for someone new to this self-hosted world.
-
-1. Your home router will have a Port Forwarding section somewhere. Log in and find it
-2. Add port forwarding for port 80 and 443 to the server hosting this project
-3. Configure your domain name details to point to your home, either with a static ip or a service like DuckDNS or [Amazon Route53](https://github.com/jc21/route53-ddns)
-4. Use the Nginx Proxy Manager as your gateway to forward to your other web based services
-
-## Quick Setup
-
-1. Install Docker and Docker-Compose
-
-- [Docker Install documentation](https://docs.docker.com/install/)
-- [Docker-Compose Install documentation](https://docs.docker.com/compose/install/)
-
-2. Create a docker-compose.yml file similar to this:
-
-```yml
-services:
- app:
- image: 'docker.io/jc21/nginx-proxy-manager:latest'
- restart: unless-stopped
- ports:
- - '80:80'
- - '81:81'
- - '443:443'
- volumes:
- - ./data:/data
- - ./letsencrypt:/etc/letsencrypt
+```
+.
+├── app/ # Next.js app router (auth, dashboard, APIs)
+├── src/
+│ └── lib/ # Database, Caddy integration, models, settings
+├── docker/ # Dockerfiles for web + Caddy
+├── compose.yaml # Production-ready docker compose definition
+└── data/ # (Generated) SQLite database, TLS material, Caddy data
```
-This is the bare minimum configuration required. See the [documentation](https://nginxproxymanager.com/setup/) for more.
+## Requirements
-3. Bring up your stack by running
+- Node.js 20+ (development)
+- Docker + Docker Compose v2 (deployment)
+- OAuth2 identity provider (OIDC compliant preferred)
+- Optional: Cloudflare DNS API token for automated certificate issuance
+
+## Quick Start
+
+1. **Install dependencies**
+
+ ```bash
+ npm install
+ ```
+
+ > Package downloads require network access.
+
+2. **Run the development server**
+
+ ```bash
+ npm run dev
+ ```
+
+3. **Configure OAuth2**
+
+ - Visit `http://localhost:3000/setup/oauth`.
+ - Supply your identity provider’s authorization, token, and userinfo endpoints plus client credentials.
+ - Sign in; the first user becomes an administrator.
+
+4. **Configure Cloudflare DNS (optional)**
+
+ - Navigate to **Settings → Cloudflare DNS**.
+ - Provide an API token with `Zone.DNS:Edit` scope and the relevant zone/account IDs.
+ - Any managed certificates attached to hosts will now request TLS via DNS validation.
+
+## Docker Compose
+
+`compose.yaml` defines a two-container stack:
+
+- `app`: Next.js server with SQLite database and certificate store in `/data`.
+- `caddy`: xcaddy-built binary with Cloudflare DNS provider and layer4 modules. The default configuration responds on `caddyproxymanager.com` and serves the required HSTS header:
+
+ ```caddyfile
+ caddyproxymanager.com {
+ header Strict-Transport-Security "max-age=63072000"
+ respond "Caddy Proxy Manager is running" 200
+ }
+ ```
+
+Launch the stack:
```bash
-docker-compose up -d
-
-# If using docker-compose-plugin
docker compose up -d
-
```
-4. Log in to the Admin UI
+Environment variables:
-When your docker container is running, connect to it on port `81` for the admin interface.
-Sometimes this can take a little bit because of the entropy of keys.
+- `SESSION_SECRET`: random 32+ character string used to sign session cookies.
+- `DATABASE_PATH`: path to the SQLite database (default `/data/app/app.db` in containers).
+- `CERTS_DIRECTORY`: directory for imported PEM files shared with the Caddy container.
+- `CADDY_API_URL`: URL for the Caddy admin API (default `http://caddy:2019` inside the compose network).
+- `PRIMARY_DOMAIN`: default domain served by the bootstrap Caddyfile (defaults to `caddyproxymanager.com`).
-[http://127.0.0.1:81](http://127.0.0.1:81)
+## Data Locations
-Default Admin User:
-```
-Email: admin@example.com
-Password: changeme
-```
+- `data/app/app.db`: SQLite database storing configuration, sessions, and audit log.
+- `data/certs/`: Imported TLS certificates and keys generated by the UI.
+- `data/caddy/`: Autogenerated Caddy state (ACME storage, etc.).
-Immediately after logging in with this default user you will be asked to modify your details and change your password.
+## UI Features
+- **Proxy Hosts:** HTTP(S) reverse proxies with HSTS, access lists, optional custom certificates, and WebSocket support.
+- **Redirects:** 301/302 responses with optional path/query preservation.
+- **Dead Hosts:** Branded responses for offline services.
+- **Streams:** TCP/UDP forwarding powered by the Caddy layer4 module.
+- **Access Lists:** Bcrypt-backed basic auth credentials, assignable to proxy hosts.
+- **Certificates:** Managed (ACME) or imported PEM certificates with audit history.
+- **Audit Log:** Chronological record of every configuration change and actor.
+- **Settings:** General metadata, OAuth2 endpoints, and Cloudflare DNS credentials.
-## Contributing
+## Development Notes
-All are welcome to create pull requests for this project, against the `develop` branch. Official releases are created from the `master` branch.
+- SQLite schema migrations are embedded in `src/lib/migrations.ts` and run automatically on startup.
+- Caddy configuration is rebuilt on every change and pushed via the admin API. Failures are surfaced to the UI.
+- OAuth2 login uses PKCE and stores session tokens as HMAC-signed cookies backed by the database.
-CI is used in this project. All PR's must pass before being considered. After passing,
-docker builds for PR's are available on dockerhub for manual verifications.
+## License
-Documentation within the `develop` branch is available for preview at
-[https://develop.nginxproxymanager.com](https://develop.nginxproxymanager.com)
-
-
-### Contributors
-
-Special thanks to [all of our contributors](https://github.com/NginxProxyManager/nginx-proxy-manager/graphs/contributors).
-
-
-## Getting Support
-
-1. [Found a bug?](https://github.com/NginxProxyManager/nginx-proxy-manager/issues)
-2. [Discussions](https://github.com/NginxProxyManager/nginx-proxy-manager/discussions)
-3. [Reddit](https://reddit.com/r/nginxproxymanager)
+MIT License © Caddy Proxy Manager contributors.
diff --git a/app/(auth)/login/page.tsx b/app/(auth)/login/page.tsx
new file mode 100644
index 00000000..81b0045c
--- /dev/null
+++ b/app/(auth)/login/page.tsx
@@ -0,0 +1,85 @@
+import { redirect } from "next/navigation";
+import { getSession } from "@/src/lib/auth/session";
+import { buildAuthorizationUrl } from "@/src/lib/auth/oauth";
+import { getOAuthSettings } from "@/src/lib/settings";
+
+export default async function LoginPage() {
+ const session = getSession();
+ if (session) {
+ redirect("/");
+ }
+
+ const oauthConfigured = Boolean(getOAuthSettings());
+
+ async function startOAuth() {
+ "use server";
+ const target = buildAuthorizationUrl("/");
+ redirect(target);
+ }
+
+ return (
+
+
Caddy Proxy Manager
+
Sign in with your organization's OAuth2 provider to continue.
+ {oauthConfigured ? (
+
+ ) : (
+
+
+ The system administrator needs to configure OAuth2 settings before logins are allowed. If this is a fresh installation, start
+ with the{" "}
+
+ OAuth setup wizard
+
+ .
+
+
+ )}
+
+
+ );
+}
diff --git a/app/(dashboard)/access-lists/actions.ts b/app/(dashboard)/access-lists/actions.ts
new file mode 100644
index 00000000..57ab8219
--- /dev/null
+++ b/app/(dashboard)/access-lists/actions.ts
@@ -0,0 +1,73 @@
+"use server";
+
+import { revalidatePath } from "next/cache";
+import { requireUser } from "@/src/lib/auth/session";
+import {
+ addAccessListEntry,
+ createAccessList,
+ deleteAccessList,
+ removeAccessListEntry,
+ updateAccessList
+} from "@/src/lib/models/access-lists";
+
+export async function createAccessListAction(formData: FormData) {
+ const { user } = requireUser();
+ const rawUsers = String(formData.get("users") ?? "");
+ const accounts = rawUsers
+ .split("\n")
+ .map((line) => line.trim())
+ .filter(Boolean)
+ .map((line) => {
+ const [username, password] = line.split(":");
+ return { username: username.trim(), password: (password ?? "").trim() };
+ })
+ .filter((item) => item.username && item.password);
+
+ await createAccessList(
+ {
+ name: String(formData.get("name") ?? "Access list"),
+ description: formData.get("description") ? String(formData.get("description")) : null,
+ users: accounts
+ },
+ user.id
+ );
+ revalidatePath("/access-lists");
+}
+
+export async function updateAccessListAction(id: number, formData: FormData) {
+ const { user } = requireUser();
+ await updateAccessList(
+ id,
+ {
+ name: formData.get("name") ? String(formData.get("name")) : undefined,
+ description: formData.get("description") ? String(formData.get("description")) : undefined
+ },
+ user.id
+ );
+ revalidatePath("/access-lists");
+}
+
+export async function deleteAccessListAction(id: number) {
+ const { user } = requireUser();
+ await deleteAccessList(id, user.id);
+ revalidatePath("/access-lists");
+}
+
+export async function addAccessEntryAction(id: number, formData: FormData) {
+ const { user } = requireUser();
+ await addAccessListEntry(
+ id,
+ {
+ username: String(formData.get("username") ?? ""),
+ password: String(formData.get("password") ?? "")
+ },
+ user.id
+ );
+ revalidatePath("/access-lists");
+}
+
+export async function deleteAccessEntryAction(accessListId: number, entryId: number) {
+ const { user } = requireUser();
+ await removeAccessListEntry(accessListId, entryId, user.id);
+ revalidatePath("/access-lists");
+}
diff --git a/app/(dashboard)/access-lists/page.tsx b/app/(dashboard)/access-lists/page.tsx
new file mode 100644
index 00000000..c8e84054
--- /dev/null
+++ b/app/(dashboard)/access-lists/page.tsx
@@ -0,0 +1,207 @@
+import { listAccessLists } from "@/src/lib/models/access-lists";
+import { addAccessEntryAction, createAccessListAction, deleteAccessEntryAction, deleteAccessListAction, updateAccessListAction } from "./actions";
+
+export default function AccessListsPage() {
+ const lists = listAccessLists();
+
+ return (
+
+
+
+
+ {lists.map((list) => (
+
+
+
+
Accounts
+ {list.entries.length === 0 ? (
+
No credentials configured.
+ ) : (
+
+ {list.entries.map((entry) => (
+
+ {entry.username}
+ deleteAccessEntryAction(list.id, entry.id)}>
+
+ Remove
+
+
+
+ ))}
+
+ )}
+
+
addAccessEntryAction(list.id, formData)} className="add-entry">
+
+
+
+ Add
+
+
+
deleteAccessListAction(list.id)}>
+
+ Delete list
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/audit-log/page.tsx b/app/(dashboard)/audit-log/page.tsx
new file mode 100644
index 00000000..1bcd7903
--- /dev/null
+++ b/app/(dashboard)/audit-log/page.tsx
@@ -0,0 +1,72 @@
+import { listAuditEvents } from "@/src/lib/models/audit";
+import { listUsers } from "@/src/lib/models/user";
+
+export default function AuditLogPage() {
+ const events = listAuditEvents(200);
+ const users = new Map(listUsers().map((user) => [user.id, user]));
+
+ return (
+
+
+
+
+
+ When
+ User
+ Action
+ Entity
+ Summary
+
+
+
+ {events.map((event) => {
+ const user = event.user_id ? users.get(event.user_id) : null;
+ return (
+
+ {new Date(event.created_at).toLocaleString()}
+ {user ? user.name ?? user.email : "System"}
+ {event.action}
+ {event.entity_type}
+ {event.summary ?? "—"}
+
+ );
+ })}
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/certificates/actions.ts b/app/(dashboard)/certificates/actions.ts
new file mode 100644
index 00000000..b7da1d3d
--- /dev/null
+++ b/app/(dashboard)/certificates/actions.ts
@@ -0,0 +1,57 @@
+"use server";
+
+import { revalidatePath } from "next/cache";
+import { requireUser } from "@/src/lib/auth/session";
+import { createCertificate, deleteCertificate, updateCertificate } from "@/src/lib/models/certificates";
+
+function parseDomains(value: FormDataEntryValue | null): string[] {
+ if (!value || typeof value !== "string") {
+ return [];
+ }
+ return value
+ .replace(/\n/g, ",")
+ .split(",")
+ .map((item) => item.trim())
+ .filter(Boolean);
+}
+
+export async function createCertificateAction(formData: FormData) {
+ const { user } = requireUser();
+ const type = String(formData.get("type") ?? "managed") as "managed" | "imported";
+ await createCertificate(
+ {
+ name: String(formData.get("name") ?? "Certificate"),
+ type,
+ domain_names: parseDomains(formData.get("domain_names")),
+ auto_renew: type === "managed" ? formData.get("auto_renew") === "on" : false,
+ certificate_pem: type === "imported" ? String(formData.get("certificate_pem") ?? "") : null,
+ private_key_pem: type === "imported" ? String(formData.get("private_key_pem") ?? "") : null
+ },
+ user.id
+ );
+ revalidatePath("/certificates");
+}
+
+export async function updateCertificateAction(id: number, formData: FormData) {
+ const { user } = requireUser();
+ const type = formData.get("type") ? (String(formData.get("type")) as "managed" | "imported") : undefined;
+ await updateCertificate(
+ id,
+ {
+ name: formData.get("name") ? String(formData.get("name")) : undefined,
+ type,
+ domain_names: formData.get("domain_names") ? parseDomains(formData.get("domain_names")) : undefined,
+ auto_renew: formData.has("auto_renew_present") ? formData.get("auto_renew") === "on" : undefined,
+ certificate_pem: formData.get("certificate_pem") ? String(formData.get("certificate_pem")) : undefined,
+ private_key_pem: formData.get("private_key_pem") ? String(formData.get("private_key_pem")) : undefined
+ },
+ user.id
+ );
+ revalidatePath("/certificates");
+}
+
+export async function deleteCertificateAction(id: number) {
+ const { user } = requireUser();
+ await deleteCertificate(id, user.id);
+ revalidatePath("/certificates");
+}
diff --git a/app/(dashboard)/certificates/page.tsx b/app/(dashboard)/certificates/page.tsx
new file mode 100644
index 00000000..f7ceb344
--- /dev/null
+++ b/app/(dashboard)/certificates/page.tsx
@@ -0,0 +1,220 @@
+import { listCertificates } from "@/src/lib/models/certificates";
+import { createCertificateAction, deleteCertificateAction, updateCertificateAction } from "./actions";
+
+export default function CertificatesPage() {
+ const certificates = listCertificates();
+
+ return (
+
+
+
+
+ {certificates.map((cert) => (
+
+
+
+
+
+
{cert.name}
+
{cert.domain_names.join(", ")}
+
+
{cert.type === "managed" ? "Managed" : "Imported"}
+
+
+ updateCertificateAction(cert.id, formData)} className="form">
+
+ Name
+
+
+
+ Domains
+
+
+
+ Type
+
+ Managed (ACME)
+ Imported
+
+
+ {cert.type === "managed" ? (
+
+
+ Auto renew
+
+ ) : (
+ <>
+
+ Certificate PEM
+
+
+
+ Private key PEM
+
+
+ >
+ )}
+
+
+ Save certificate
+
+
+
+
+
deleteCertificateAction(cert.id)}>
+
+ Delete
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/dead-hosts/actions.ts b/app/(dashboard)/dead-hosts/actions.ts
new file mode 100644
index 00000000..b713b49a
--- /dev/null
+++ b/app/(dashboard)/dead-hosts/actions.ts
@@ -0,0 +1,53 @@
+"use server";
+
+import { revalidatePath } from "next/cache";
+import { requireUser } from "@/src/lib/auth/session";
+import { createDeadHost, deleteDeadHost, updateDeadHost } from "@/src/lib/models/dead-hosts";
+
+function parseDomains(value: FormDataEntryValue | null): string[] {
+ if (!value || typeof value !== "string") {
+ return [];
+ }
+ return value
+ .replace(/\n/g, ",")
+ .split(",")
+ .map((item) => item.trim())
+ .filter(Boolean);
+}
+
+export async function createDeadHostAction(formData: FormData) {
+ const { user } = requireUser();
+ await createDeadHost(
+ {
+ name: String(formData.get("name") ?? "Dead host"),
+ domains: parseDomains(formData.get("domains")),
+ status_code: formData.get("status_code") ? Number(formData.get("status_code")) : 503,
+ response_body: formData.get("response_body") ? String(formData.get("response_body")) : null,
+ enabled: formData.has("enabled") ? formData.get("enabled") === "on" : true
+ },
+ user.id
+ );
+ revalidatePath("/dead-hosts");
+}
+
+export async function updateDeadHostAction(id: number, formData: FormData) {
+ const { user } = requireUser();
+ await updateDeadHost(
+ id,
+ {
+ name: formData.get("name") ? String(formData.get("name")) : undefined,
+ domains: formData.get("domains") ? parseDomains(formData.get("domains")) : undefined,
+ status_code: formData.get("status_code") ? Number(formData.get("status_code")) : undefined,
+ response_body: formData.get("response_body") ? String(formData.get("response_body")) : undefined,
+ enabled: formData.has("enabled_present") ? formData.get("enabled") === "on" : undefined
+ },
+ user.id
+ );
+ revalidatePath("/dead-hosts");
+}
+
+export async function deleteDeadHostAction(id: number) {
+ const { user } = requireUser();
+ await deleteDeadHost(id, user.id);
+ revalidatePath("/dead-hosts");
+}
diff --git a/app/(dashboard)/dead-hosts/page.tsx b/app/(dashboard)/dead-hosts/page.tsx
new file mode 100644
index 00000000..dc6c4610
--- /dev/null
+++ b/app/(dashboard)/dead-hosts/page.tsx
@@ -0,0 +1,201 @@
+import { listDeadHosts } from "@/src/lib/models/dead-hosts";
+import { createDeadHostAction, deleteDeadHostAction, updateDeadHostAction } from "./actions";
+
+export default function DeadHostsPage() {
+ const hosts = listDeadHosts();
+
+ return (
+
+
+
+
+ {hosts.map((host) => (
+
+
+
+
{host.name}
+
{host.domains.join(", ")}
+
+
{host.enabled ? "Enabled" : "Disabled"}
+
+
+ Edit
+ updateDeadHostAction(host.id, formData)} className="form">
+
+ Name
+
+
+
+ Domains
+
+
+
+ Status code
+
+
+
+ Response body (optional)
+
+
+
+
+ Enabled
+
+
+
+ Save
+
+
+
+
+
deleteDeadHostAction(host.id)}>
+
+ Delete
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/layout.tsx b/app/(dashboard)/layout.tsx
new file mode 100644
index 00000000..c76959a2
--- /dev/null
+++ b/app/(dashboard)/layout.tsx
@@ -0,0 +1,63 @@
+import { ReactNode } from "react";
+import { requireUser } from "@/src/lib/auth/session";
+import { NavLinks } from "./nav-links";
+
+export default function DashboardLayout({ children }: { children: ReactNode }) {
+ const { user } = requireUser();
+
+ return (
+
+ );
+}
diff --git a/app/(dashboard)/nav-links.tsx b/app/(dashboard)/nav-links.tsx
new file mode 100644
index 00000000..b173a5e0
--- /dev/null
+++ b/app/(dashboard)/nav-links.tsx
@@ -0,0 +1,50 @@
+"use client";
+
+import Link from "next/link";
+import { usePathname } from "next/navigation";
+
+const NAV_LINKS = [
+ { href: "/", label: "Overview" },
+ { href: "/proxy-hosts", label: "Proxy Hosts" },
+ { href: "/redirects", label: "Redirects" },
+ { href: "/dead-hosts", label: "Dead Hosts" },
+ { href: "/streams", label: "Streams" },
+ { href: "/access-lists", label: "Access Lists" },
+ { href: "/certificates", label: "Certificates" },
+ { href: "/settings", label: "Settings" },
+ { href: "/audit-log", label: "Audit Log" }
+];
+
+export function NavLinks() {
+ const pathname = usePathname();
+ return (
+
+ {NAV_LINKS.map((link) => {
+ const isActive = pathname === link.href;
+ return (
+
+ {link.label}
+
+ );
+ })}
+
+
+ );
+}
diff --git a/app/(dashboard)/page.tsx b/app/(dashboard)/page.tsx
new file mode 100644
index 00000000..a9a5e9cb
--- /dev/null
+++ b/app/(dashboard)/page.tsx
@@ -0,0 +1,183 @@
+import Link from "next/link";
+import db from "@/src/lib/db";
+import { requireUser } from "@/src/lib/auth/session";
+
+type StatCard = {
+ label: string;
+ icon: string;
+ count: number;
+ href: string;
+};
+
+function loadStats(): StatCard[] {
+ const metrics = [
+ {
+ label: "Proxy Hosts",
+ table: "proxy_hosts",
+ href: "/proxy-hosts",
+ icon: "⇄"
+ },
+ {
+ label: "Redirects",
+ table: "redirect_hosts",
+ href: "/redirects",
+ icon: "↪"
+ },
+ {
+ label: "Dead Hosts",
+ table: "dead_hosts",
+ href: "/dead-hosts",
+ icon: "☠"
+ },
+ {
+ label: "Streams",
+ table: "stream_hosts",
+ href: "/streams",
+ icon: "≋"
+ },
+ {
+ label: "Certificates",
+ table: "certificates",
+ href: "/certificates",
+ icon: "🔐"
+ },
+ {
+ label: "Access Lists",
+ table: "access_lists",
+ href: "/access-lists",
+ icon: "🔒"
+ }
+ ] as const;
+
+ return metrics.map((metric) => {
+ const row = db.prepare(`SELECT COUNT(*) as count FROM ${metric.table}`).get() as { count: number };
+ return {
+ label: metric.label,
+ icon: metric.icon,
+ count: Number(row.count),
+ href: metric.href
+ };
+ });
+}
+
+export default function OverviewPage() {
+ const { user } = requireUser();
+ const stats = loadStats();
+
+ const recentEvents = db
+ .prepare(
+ `SELECT action, entity_type, summary, created_at
+ FROM audit_events
+ ORDER BY created_at DESC
+ LIMIT 8`
+ )
+ .all() as { action: string; entity_type: string; summary: string | null; created_at: string }[];
+
+ return (
+
+
+
+ {stats.map((stat) => (
+
+ {stat.icon}
+ {stat.count}
+ {stat.label}
+
+ ))}
+
+
+ Recent Activity
+ {recentEvents.length === 0 ? (
+ No activity recorded yet.
+ ) : (
+
+ {recentEvents.map((event, index) => (
+
+ {event.summary ?? `${event.action} on ${event.entity_type}`}
+ {new Date(event.created_at).toLocaleString()}
+
+ ))}
+
+ )}
+
+
+
+ );
+}
diff --git a/app/(dashboard)/proxy-hosts/actions.ts b/app/(dashboard)/proxy-hosts/actions.ts
new file mode 100644
index 00000000..6cc7e749
--- /dev/null
+++ b/app/(dashboard)/proxy-hosts/actions.ts
@@ -0,0 +1,70 @@
+"use server";
+
+import { revalidatePath } from "next/cache";
+import { requireUser } from "@/src/lib/auth/session";
+import { createProxyHost, deleteProxyHost, updateProxyHost } from "@/src/lib/models/proxy-hosts";
+
+function parseCsv(value: FormDataEntryValue | null): string[] {
+ if (!value || typeof value !== "string") {
+ return [];
+ }
+ return value
+ .replace(/\n/g, ",")
+ .split(",")
+ .map((item) => item.trim())
+ .filter(Boolean);
+}
+
+function parseCheckbox(value: FormDataEntryValue | null): boolean {
+ return value === "on" || value === "true" || value === "1";
+}
+
+export async function createProxyHostAction(formData: FormData) {
+ const { user } = requireUser();
+ await createProxyHost(
+ {
+ name: String(formData.get("name") ?? "Untitled"),
+ domains: parseCsv(formData.get("domains")),
+ upstreams: parseCsv(formData.get("upstreams")),
+ certificate_id: formData.get("certificate_id") ? Number(formData.get("certificate_id")) : null,
+ access_list_id: formData.get("access_list_id") ? Number(formData.get("access_list_id")) : null,
+ ssl_forced: parseCheckbox(formData.get("ssl_forced")),
+ hsts_enabled: parseCheckbox(formData.get("hsts_enabled")),
+ hsts_subdomains: parseCheckbox(formData.get("hsts_subdomains")),
+ allow_websocket: parseCheckbox(formData.get("allow_websocket")),
+ preserve_host_header: parseCheckbox(formData.get("preserve_host_header")),
+ enabled: parseCheckbox(formData.get("enabled"))
+ },
+ user.id
+ );
+ revalidatePath("/proxy-hosts");
+}
+
+export async function updateProxyHostAction(id: number, formData: FormData) {
+ const { user } = requireUser();
+ const boolField = (key: string) => (formData.has(`${key}_present`) ? parseCheckbox(formData.get(key)) : undefined);
+ await updateProxyHost(
+ id,
+ {
+ name: formData.get("name") ? String(formData.get("name")) : undefined,
+ domains: formData.get("domains") ? parseCsv(formData.get("domains")) : undefined,
+ upstreams: formData.get("upstreams") ? parseCsv(formData.get("upstreams")) : undefined,
+ certificate_id: formData.get("certificate_id") ? Number(formData.get("certificate_id")) : undefined,
+ access_list_id: formData.get("access_list_id") ? Number(formData.get("access_list_id")) : undefined,
+ ssl_forced: boolField("ssl_forced"),
+ hsts_enabled: boolField("hsts_enabled"),
+ hsts_subdomains: boolField("hsts_subdomains"),
+ allow_websocket: boolField("allow_websocket"),
+ preserve_host_header: boolField("preserve_host_header"),
+ enabled: boolField("enabled")
+ },
+ user.id
+ );
+ revalidatePath("/proxy-hosts");
+}
+
+export async function deleteProxyHostAction(id: number) {
+ const { user } = requireUser();
+ await deleteProxyHost(id, user.id);
+ revalidatePath("/proxy-hosts");
+}
diff --git a/app/(dashboard)/proxy-hosts/page.tsx b/app/(dashboard)/proxy-hosts/page.tsx
new file mode 100644
index 00000000..b7084cba
--- /dev/null
+++ b/app/(dashboard)/proxy-hosts/page.tsx
@@ -0,0 +1,290 @@
+import { createProxyHostAction, deleteProxyHostAction, updateProxyHostAction } from "./actions";
+import { listProxyHosts } from "@/src/lib/models/proxy-hosts";
+import { listCertificates } from "@/src/lib/models/certificates";
+import { listAccessLists } from "@/src/lib/models/access-lists";
+
+export default function ProxyHostsPage() {
+ const hosts = listProxyHosts();
+ const certificates = listCertificates();
+ const accessLists = listAccessLists();
+
+ return (
+
+
+
+
+ {hosts.map((host) => (
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/redirects/actions.ts b/app/(dashboard)/redirects/actions.ts
new file mode 100644
index 00000000..6f492983
--- /dev/null
+++ b/app/(dashboard)/redirects/actions.ts
@@ -0,0 +1,55 @@
+"use server";
+
+import { revalidatePath } from "next/cache";
+import { requireUser } from "@/src/lib/auth/session";
+import { createRedirectHost, deleteRedirectHost, updateRedirectHost } from "@/src/lib/models/redirect-hosts";
+
+function parseList(value: FormDataEntryValue | null): string[] {
+ if (!value || typeof value !== "string") {
+ return [];
+ }
+ return value
+ .replace(/\n/g, ",")
+ .split(",")
+ .map((item) => item.trim())
+ .filter(Boolean);
+}
+
+export async function createRedirectAction(formData: FormData) {
+ const { user } = requireUser();
+ await createRedirectHost(
+ {
+ name: String(formData.get("name") ?? "Redirect"),
+ domains: parseList(formData.get("domains")),
+ destination: String(formData.get("destination") ?? ""),
+ status_code: formData.get("status_code") ? Number(formData.get("status_code")) : 302,
+ preserve_query: formData.get("preserve_query") === "on",
+ enabled: formData.has("enabled") ? formData.get("enabled") === "on" : true
+ },
+ user.id
+ );
+ revalidatePath("/redirects");
+}
+
+export async function updateRedirectAction(id: number, formData: FormData) {
+ const { user } = requireUser();
+ await updateRedirectHost(
+ id,
+ {
+ name: formData.get("name") ? String(formData.get("name")) : undefined,
+ domains: formData.get("domains") ? parseList(formData.get("domains")) : undefined,
+ destination: formData.get("destination") ? String(formData.get("destination")) : undefined,
+ status_code: formData.get("status_code") ? Number(formData.get("status_code")) : undefined,
+ preserve_query: formData.has("preserve_query_present") ? formData.get("preserve_query") === "on" : undefined,
+ enabled: formData.has("enabled_present") ? formData.get("enabled") === "on" : undefined
+ },
+ user.id
+ );
+ revalidatePath("/redirects");
+}
+
+export async function deleteRedirectAction(id: number) {
+ const { user } = requireUser();
+ await deleteRedirectHost(id, user.id);
+ revalidatePath("/redirects");
+}
diff --git a/app/(dashboard)/redirects/page.tsx b/app/(dashboard)/redirects/page.tsx
new file mode 100644
index 00000000..f7b23275
--- /dev/null
+++ b/app/(dashboard)/redirects/page.tsx
@@ -0,0 +1,217 @@
+import { listRedirectHosts } from "@/src/lib/models/redirect-hosts";
+import { createRedirectAction, deleteRedirectAction, updateRedirectAction } from "./actions";
+
+export default function RedirectsPage() {
+ const redirects = listRedirectHosts();
+
+ return (
+
+
+
+
+ {redirects.map((redirect) => (
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/app/(dashboard)/settings/actions.ts b/app/(dashboard)/settings/actions.ts
new file mode 100644
index 00000000..a69eb4d1
--- /dev/null
+++ b/app/(dashboard)/settings/actions.ts
@@ -0,0 +1,47 @@
+"use server";
+
+import { revalidatePath } from "next/cache";
+import { requireUser } from "@/src/lib/auth/session";
+import { applyCaddyConfig } from "@/src/lib/caddy";
+import { saveCloudflareSettings, saveGeneralSettings, saveOAuthSettings } from "@/src/lib/settings";
+
+export async function updateGeneralSettingsAction(formData: FormData) {
+ requireUser(); // ensure authenticated
+ saveGeneralSettings({
+ primaryDomain: String(formData.get("primaryDomain") ?? ""),
+ acmeEmail: formData.get("acmeEmail") ? String(formData.get("acmeEmail")) : undefined
+ });
+ revalidatePath("/settings");
+}
+
+export async function updateOAuthSettingsAction(formData: FormData) {
+ requireUser();
+ saveOAuthSettings({
+ authorizationUrl: String(formData.get("authorizationUrl") ?? ""),
+ tokenUrl: String(formData.get("tokenUrl") ?? ""),
+ clientId: String(formData.get("clientId") ?? ""),
+ clientSecret: String(formData.get("clientSecret") ?? ""),
+ userInfoUrl: String(formData.get("userInfoUrl") ?? ""),
+ scopes: String(formData.get("scopes") ?? ""),
+ emailClaim: formData.get("emailClaim") ? String(formData.get("emailClaim")) : undefined,
+ nameClaim: formData.get("nameClaim") ? String(formData.get("nameClaim")) : undefined,
+ avatarClaim: formData.get("avatarClaim") ? String(formData.get("avatarClaim")) : undefined
+ });
+ revalidatePath("/settings");
+}
+
+export async function updateCloudflareSettingsAction(formData: FormData) {
+ requireUser();
+ const apiToken = String(formData.get("apiToken") ?? "");
+ if (!apiToken) {
+ saveCloudflareSettings({ apiToken: "", zoneId: undefined, accountId: undefined });
+ } else {
+ saveCloudflareSettings({
+ apiToken,
+ zoneId: formData.get("zoneId") ? String(formData.get("zoneId")) : undefined,
+ accountId: formData.get("accountId") ? String(formData.get("accountId")) : undefined
+ });
+ }
+ await applyCaddyConfig();
+ revalidatePath("/settings");
+}
diff --git a/app/(dashboard)/settings/page.tsx b/app/(dashboard)/settings/page.tsx
new file mode 100644
index 00000000..b2636c7a
--- /dev/null
+++ b/app/(dashboard)/settings/page.tsx
@@ -0,0 +1,180 @@
+import { getCloudflareSettings, getGeneralSettings, getOAuthSettings } from "@/src/lib/settings";
+import { updateCloudflareSettingsAction, updateGeneralSettingsAction, updateOAuthSettingsAction } from "./actions";
+
+export default function SettingsPage() {
+ const general = getGeneralSettings();
+ const oauth = getOAuthSettings();
+ const cloudflare = getCloudflareSettings();
+
+ return (
+
+ );
+}
diff --git a/app/(dashboard)/streams/actions.ts b/app/(dashboard)/streams/actions.ts
new file mode 100644
index 00000000..17dee01b
--- /dev/null
+++ b/app/(dashboard)/streams/actions.ts
@@ -0,0 +1,42 @@
+"use server";
+
+import { revalidatePath } from "next/cache";
+import { requireUser } from "@/src/lib/auth/session";
+import { createStreamHost, deleteStreamHost, updateStreamHost } from "@/src/lib/models/stream-hosts";
+
+export async function createStreamAction(formData: FormData) {
+ const { user } = requireUser();
+ await createStreamHost(
+ {
+ name: String(formData.get("name") ?? "Stream"),
+ listen_port: Number(formData.get("listen_port")),
+ protocol: String(formData.get("protocol") ?? "tcp"),
+ upstream: String(formData.get("upstream") ?? ""),
+ enabled: formData.has("enabled") ? formData.get("enabled") === "on" : true
+ },
+ user.id
+ );
+ revalidatePath("/streams");
+}
+
+export async function updateStreamAction(id: number, formData: FormData) {
+ const { user } = requireUser();
+ await updateStreamHost(
+ id,
+ {
+ name: formData.get("name") ? String(formData.get("name")) : undefined,
+ listen_port: formData.get("listen_port") ? Number(formData.get("listen_port")) : undefined,
+ protocol: formData.get("protocol") ? String(formData.get("protocol")) : undefined,
+ upstream: formData.get("upstream") ? String(formData.get("upstream")) : undefined,
+ enabled: formData.has("enabled_present") ? formData.get("enabled") === "on" : undefined
+ },
+ user.id
+ );
+ revalidatePath("/streams");
+}
+
+export async function deleteStreamAction(id: number) {
+ const { user } = requireUser();
+ await deleteStreamHost(id, user.id);
+ revalidatePath("/streams");
+}
diff --git a/app/(dashboard)/streams/page.tsx b/app/(dashboard)/streams/page.tsx
new file mode 100644
index 00000000..c78361da
--- /dev/null
+++ b/app/(dashboard)/streams/page.tsx
@@ -0,0 +1,209 @@
+import { listStreamHosts } from "@/src/lib/models/stream-hosts";
+import { createStreamAction, deleteStreamAction, updateStreamAction } from "./actions";
+
+export default function StreamsPage() {
+ const streams = listStreamHosts();
+
+ return (
+
+
+
+
+ {streams.map((stream) => (
+
+
+
+
{stream.name}
+
+ Listens on :{stream.listen_port} ({stream.protocol.toUpperCase()}) ➜ {stream.upstream}
+
+
+
{stream.enabled ? "Enabled" : "Disabled"}
+
+
+ Edit
+ updateStreamAction(stream.id, formData)} className="form">
+
+ Name
+
+
+
+ Listen port
+
+
+
+ Protocol
+
+ TCP
+ UDP
+
+
+
+ Upstream
+
+
+
+
+ Enabled
+
+
+
+ Save
+
+
+
+
+
deleteStreamAction(stream.id)}>
+
+ Delete
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+}
diff --git a/app/api/auth/callback/route.ts b/app/api/auth/callback/route.ts
new file mode 100644
index 00000000..ce436b44
--- /dev/null
+++ b/app/api/auth/callback/route.ts
@@ -0,0 +1,24 @@
+import { NextRequest, NextResponse } from "next/server";
+import { finalizeOAuthLogin } from "@/src/lib/auth/oauth";
+import { createSession } from "@/src/lib/auth/session";
+import { config } from "@/src/lib/config";
+
+export async function GET(request: NextRequest) {
+ const url = new URL(request.url);
+ const code = url.searchParams.get("code");
+ const state = url.searchParams.get("state");
+
+ if (!code || !state) {
+ return NextResponse.redirect(new URL("/login?error=invalid_response", config.baseUrl));
+ }
+
+ try {
+ const { user, redirectTo } = await finalizeOAuthLogin(code, state);
+ createSession(user.id);
+ const destination = redirectTo && redirectTo.startsWith("/") ? redirectTo : "/";
+ return NextResponse.redirect(new URL(destination, config.baseUrl));
+ } catch (error) {
+ console.error("OAuth callback failed", error);
+ return NextResponse.redirect(new URL("/login?error=oauth_failed", config.baseUrl));
+ }
+}
diff --git a/app/api/auth/logout/route.ts b/app/api/auth/logout/route.ts
new file mode 100644
index 00000000..29869d2e
--- /dev/null
+++ b/app/api/auth/logout/route.ts
@@ -0,0 +1,8 @@
+import { NextResponse } from "next/server";
+import { destroySession } from "@/src/lib/auth/session";
+import { config } from "@/src/lib/config";
+
+export async function POST() {
+ destroySession();
+ return NextResponse.redirect(new URL("/login", config.baseUrl));
+}
diff --git a/app/globals.css b/app/globals.css
new file mode 100644
index 00000000..cd6a029a
--- /dev/null
+++ b/app/globals.css
@@ -0,0 +1,31 @@
+:root {
+ color-scheme: light dark;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+html,
+body {
+ padding: 0;
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
+ background: #0a0d13;
+ color: #f9fafc;
+}
+
+a {
+ color: inherit;
+ text-decoration: none;
+}
+
+button {
+ font: inherit;
+}
+
+input,
+select,
+textarea {
+ font: inherit;
+}
diff --git a/app/layout.tsx b/app/layout.tsx
new file mode 100644
index 00000000..8bbd8c17
--- /dev/null
+++ b/app/layout.tsx
@@ -0,0 +1,12 @@
+"use client";
+
+import "./globals.css";
+import { ReactNode } from "react";
+
+export default function RootLayout({ children }: { children: ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/setup/oauth/actions.ts b/app/setup/oauth/actions.ts
new file mode 100644
index 00000000..b34d8d1a
--- /dev/null
+++ b/app/setup/oauth/actions.ts
@@ -0,0 +1,23 @@
+"use server";
+
+import { redirect } from "next/navigation";
+import { getUserCount } from "@/src/lib/models/user";
+import { saveOAuthSettings } from "@/src/lib/settings";
+
+export async function initialOAuthSetupAction(formData: FormData) {
+ if (getUserCount() > 0) {
+ redirect("/login");
+ }
+ saveOAuthSettings({
+ authorizationUrl: String(formData.get("authorizationUrl") ?? ""),
+ tokenUrl: String(formData.get("tokenUrl") ?? ""),
+ userInfoUrl: String(formData.get("userInfoUrl") ?? ""),
+ clientId: String(formData.get("clientId") ?? ""),
+ clientSecret: String(formData.get("clientSecret") ?? ""),
+ scopes: String(formData.get("scopes") ?? ""),
+ emailClaim: formData.get("emailClaim") ? String(formData.get("emailClaim")) : undefined,
+ nameClaim: formData.get("nameClaim") ? String(formData.get("nameClaim")) : undefined,
+ avatarClaim: formData.get("avatarClaim") ? String(formData.get("avatarClaim")) : undefined
+ });
+ redirect("/login");
+}
diff --git a/app/setup/oauth/page.tsx b/app/setup/oauth/page.tsx
new file mode 100644
index 00000000..e164cbfa
--- /dev/null
+++ b/app/setup/oauth/page.tsx
@@ -0,0 +1,128 @@
+import { redirect } from "next/navigation";
+import { getOAuthSettings } from "@/src/lib/settings";
+import { getUserCount } from "@/src/lib/models/user";
+import { initialOAuthSetupAction } from "./actions";
+
+export default function OAuthSetupPage() {
+ if (getUserCount() > 0 && getOAuthSettings()) {
+ redirect("/login");
+ }
+
+ return (
+
+ );
+}
diff --git a/backend/.eslintrc.json b/backend/.eslintrc.json
deleted file mode 100644
index 6d6172a4..00000000
--- a/backend/.eslintrc.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "env": {
- "node": true,
- "es6": true
- },
- "extends": [
- "eslint:recommended"
- ],
- "globals": {
- "Atomics": "readonly",
- "SharedArrayBuffer": "readonly"
- },
- "parserOptions": {
- "ecmaVersion": 2018,
- "sourceType": "module"
- },
- "plugins": [
- "align-assignments"
- ],
- "rules": {
- "arrow-parens": [
- "error",
- "always"
- ],
- "indent": [
- "error",
- "tab"
- ],
- "linebreak-style": [
- "error",
- "unix"
- ],
- "quotes": [
- "error",
- "single"
- ],
- "semi": [
- "error",
- "always"
- ],
- "key-spacing": [
- "error",
- {
- "align": "value"
- }
- ],
- "comma-spacing": [
- "error",
- {
- "before": false,
- "after": true
- }
- ],
- "func-call-spacing": [
- "error",
- "never"
- ],
- "keyword-spacing": [
- "error",
- {
- "before": true
- }
- ],
- "no-irregular-whitespace": "error",
- "no-unused-expressions": 0,
- "align-assignments/align-assignments": [
- 2,
- {
- "requiresOnly": false
- }
- ]
- }
-}
\ No newline at end of file
diff --git a/backend/.gitignore b/backend/.gitignore
deleted file mode 100644
index 149080b9..00000000
--- a/backend/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-config/development.json
-data/*
-yarn-error.log
-tmp
-certbot.log
-node_modules
-core.*
-
diff --git a/backend/.prettierrc b/backend/.prettierrc
deleted file mode 100644
index fefbcfa6..00000000
--- a/backend/.prettierrc
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "printWidth": 320,
- "tabWidth": 4,
- "useTabs": true,
- "semi": true,
- "singleQuote": true,
- "bracketSpacing": true,
- "jsxBracketSameLine": true,
- "trailingComma": "all",
- "proseWrap": "always"
-}
diff --git a/backend/app.js b/backend/app.js
deleted file mode 100644
index 59f7def2..00000000
--- a/backend/app.js
+++ /dev/null
@@ -1,90 +0,0 @@
-const express = require('express');
-const bodyParser = require('body-parser');
-const fileUpload = require('express-fileupload');
-const compression = require('compression');
-const config = require('./lib/config');
-const log = require('./logger').express;
-
-/**
- * App
- */
-const app = express();
-app.use(fileUpload());
-app.use(bodyParser.json());
-app.use(bodyParser.urlencoded({extended: true}));
-
-// Gzip
-app.use(compression());
-
-/**
- * General Logging, BEFORE routes
- */
-
-app.disable('x-powered-by');
-app.enable('trust proxy', ['loopback', 'linklocal', 'uniquelocal']);
-app.enable('strict routing');
-
-// pretty print JSON when not live
-if (config.debug()) {
- app.set('json spaces', 2);
-}
-
-// CORS for everything
-app.use(require('./lib/express/cors'));
-
-// General security/cache related headers + server header
-app.use(function (req, res, next) {
- let x_frame_options = 'DENY';
-
- if (typeof process.env.X_FRAME_OPTIONS !== 'undefined' && process.env.X_FRAME_OPTIONS) {
- x_frame_options = process.env.X_FRAME_OPTIONS;
- }
-
- res.set({
- 'X-XSS-Protection': '1; mode=block',
- 'X-Content-Type-Options': 'nosniff',
- 'X-Frame-Options': x_frame_options,
- 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
- Pragma: 'no-cache',
- Expires: 0
- });
- next();
-});
-
-app.use(require('./lib/express/jwt')());
-app.use('/', require('./routes/main'));
-
-// production error handler
-// no stacktraces leaked to user
-// eslint-disable-next-line
-app.use(function (err, req, res, next) {
-
- let payload = {
- error: {
- code: err.status,
- message: err.public ? err.message : 'Internal Error'
- }
- };
-
- if (config.debug() || (req.baseUrl + req.path).includes('nginx/certificates')) {
- payload.debug = {
- stack: typeof err.stack !== 'undefined' && err.stack ? err.stack.split('\n') : null,
- previous: err.previous
- };
- }
-
- // Not every error is worth logging - but this is good for now until it gets annoying.
- if (typeof err.stack !== 'undefined' && err.stack) {
- if (config.debug()) {
- log.debug(err.stack);
- } else if (typeof err.public == 'undefined' || !err.public) {
- log.warn(err.message);
- }
- }
-
- res
- .status(err.status || 500)
- .send(payload);
-});
-
-module.exports = app;
diff --git a/backend/config/README.md b/backend/config/README.md
deleted file mode 100644
index 26268a11..00000000
--- a/backend/config/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-These files are use in development and are not deployed as part of the final product.
-
\ No newline at end of file
diff --git a/backend/config/default.json b/backend/config/default.json
deleted file mode 100644
index 154e66e4..00000000
--- a/backend/config/default.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "database": {
- "engine": "mysql2",
- "host": "db",
- "name": "npm",
- "user": "npm",
- "password": "npm",
- "port": 3306
- }
-}
diff --git a/backend/config/sqlite-test-db.json b/backend/config/sqlite-test-db.json
deleted file mode 100644
index ad548865..00000000
--- a/backend/config/sqlite-test-db.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "database": {
- "engine": "knex-native",
- "knex": {
- "client": "sqlite3",
- "connection": {
- "filename": "/app/config/mydb.sqlite"
- },
- "pool": {
- "min": 0,
- "max": 1,
- "createTimeoutMillis": 3000,
- "acquireTimeoutMillis": 30000,
- "idleTimeoutMillis": 30000,
- "reapIntervalMillis": 1000,
- "createRetryIntervalMillis": 100,
- "propagateCreateError": false
- },
- "migrations": {
- "tableName": "migrations",
- "stub": "src/backend/lib/migrate_template.js",
- "directory": "src/backend/migrations"
- }
- }
- }
-}
diff --git a/backend/db.js b/backend/db.js
deleted file mode 100644
index 1a8b1634..00000000
--- a/backend/db.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const config = require('./lib/config');
-
-if (!config.has('database')) {
- throw new Error('Database config does not exist! Please read the instructions: https://nginxproxymanager.com/setup/');
-}
-
-function generateDbConfig() {
- const cfg = config.get('database');
- if (cfg.engine === 'knex-native') {
- return cfg.knex;
- }
- return {
- client: cfg.engine,
- connection: {
- host: cfg.host,
- user: cfg.user,
- password: cfg.password,
- database: cfg.name,
- port: cfg.port
- },
- migrations: {
- tableName: 'migrations'
- }
- };
-}
-
-module.exports = require('knex')(generateDbConfig());
diff --git a/backend/index.js b/backend/index.js
deleted file mode 100644
index d334a7c2..00000000
--- a/backend/index.js
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env node
-
-const schema = require('./schema');
-const logger = require('./logger').global;
-
-const IP_RANGES_FETCH_ENABLED = process.env.IP_RANGES_FETCH_ENABLED !== 'false';
-
-async function appStart () {
- const migrate = require('./migrate');
- const setup = require('./setup');
- const app = require('./app');
- const internalCertificate = require('./internal/certificate');
- const internalIpRanges = require('./internal/ip_ranges');
-
- return migrate.latest()
- .then(setup)
- .then(schema.getCompiledSchema)
- .then(() => {
- if (IP_RANGES_FETCH_ENABLED) {
- logger.info('IP Ranges fetch is enabled');
- return internalIpRanges.fetch().catch((err) => {
- logger.error('IP Ranges fetch failed, continuing anyway:', err.message);
- });
- } else {
- logger.info('IP Ranges fetch is disabled by environment variable');
- }
- })
- .then(() => {
- internalCertificate.initTimer();
- internalIpRanges.initTimer();
-
- const server = app.listen(3000, () => {
- logger.info('Backend PID ' + process.pid + ' listening on port 3000 ...');
-
- process.on('SIGTERM', () => {
- logger.info('PID ' + process.pid + ' received SIGTERM');
- server.close(() => {
- logger.info('Stopping.');
- process.exit(0);
- });
- });
- });
- })
- .catch((err) => {
- logger.error(err.message, err);
- setTimeout(appStart, 1000);
- });
-}
-
-try {
- appStart();
-} catch (err) {
- logger.error(err.message, err);
- process.exit(1);
-}
-
diff --git a/backend/internal/access-list.js b/backend/internal/access-list.js
deleted file mode 100644
index 2407a0ac..00000000
--- a/backend/internal/access-list.js
+++ /dev/null
@@ -1,540 +0,0 @@
-const _ = require('lodash');
-const fs = require('node:fs');
-const batchflow = require('batchflow');
-const logger = require('../logger').access;
-const error = require('../lib/error');
-const utils = require('../lib/utils');
-const accessListModel = require('../models/access_list');
-const accessListAuthModel = require('../models/access_list_auth');
-const accessListClientModel = require('../models/access_list_client');
-const proxyHostModel = require('../models/proxy_host');
-const internalAuditLog = require('./audit-log');
-const internalNginx = require('./nginx');
-
-function omissions () {
- return ['is_deleted'];
-}
-
-const internalAccessList = {
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @returns {Promise}
- */
- create: (access, data) => {
- return access.can('access_lists:create', data)
- .then((/*access_data*/) => {
- return accessListModel
- .query()
- .insertAndFetch({
- name: data.name,
- satisfy_any: data.satisfy_any,
- pass_auth: data.pass_auth,
- owner_user_id: access.token.getUserId(1)
- })
- .then(utils.omitRow(omissions()));
- })
- .then((row) => {
- data.id = row.id;
-
- const promises = [];
-
- // Now add the items
- data.items.map((item) => {
- promises.push(accessListAuthModel
- .query()
- .insert({
- access_list_id: row.id,
- username: item.username,
- password: item.password
- })
- );
- });
-
- // Now add the clients
- if (typeof data.clients !== 'undefined' && data.clients) {
- data.clients.map((client) => {
- promises.push(accessListClientModel
- .query()
- .insert({
- access_list_id: row.id,
- address: client.address,
- directive: client.directive
- })
- );
- });
- }
-
- return Promise.all(promises);
- })
- .then(() => {
- // re-fetch with expansions
- return internalAccessList.get(access, {
- id: data.id,
- expand: ['owner', 'items', 'clients', 'proxy_hosts.access_list.[clients,items]']
- }, true /* <- skip masking */);
- })
- .then((row) => {
- // Audit log
- data.meta = _.assign({}, data.meta || {}, row.meta);
-
- return internalAccessList.build(row)
- .then(() => {
- if (parseInt(row.proxy_host_count, 10)) {
- return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
- }
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'created',
- object_type: 'access-list',
- object_id: row.id,
- meta: internalAccessList.maskItems(data)
- });
- })
- .then(() => {
- return internalAccessList.maskItems(row);
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Integer} data.id
- * @param {String} [data.name]
- * @param {String} [data.items]
- * @return {Promise}
- */
- update: (access, data) => {
- return access.can('access_lists:update', data.id)
- .then((/*access_data*/) => {
- return internalAccessList.get(access, {id: data.id});
- })
- .then((row) => {
- if (row.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError(`Access List could not be updated, IDs do not match: ${row.id} !== ${data.id}`);
- }
- })
- .then(() => {
- // patch name if specified
- if (typeof data.name !== 'undefined' && data.name) {
- return accessListModel
- .query()
- .where({id: data.id})
- .patch({
- name: data.name,
- satisfy_any: data.satisfy_any,
- pass_auth: data.pass_auth,
- });
- }
- })
- .then(() => {
- // Check for items and add/update/remove them
- if (typeof data.items !== 'undefined' && data.items) {
- const promises = [];
- const items_to_keep = [];
-
- data.items.map((item) => {
- if (item.password) {
- promises.push(accessListAuthModel
- .query()
- .insert({
- access_list_id: data.id,
- username: item.username,
- password: item.password
- })
- );
- } else {
- // This was supplied with an empty password, which means keep it but don't change the password
- items_to_keep.push(item.username);
- }
- });
-
- const query = accessListAuthModel
- .query()
- .delete()
- .where('access_list_id', data.id);
-
- if (items_to_keep.length) {
- query.andWhere('username', 'NOT IN', items_to_keep);
- }
-
- return query
- .then(() => {
- // Add new items
- if (promises.length) {
- return Promise.all(promises);
- }
- });
- }
- })
- .then(() => {
- // Check for clients and add/update/remove them
- if (typeof data.clients !== 'undefined' && data.clients) {
- const promises = [];
-
- data.clients.map((client) => {
- if (client.address) {
- promises.push(accessListClientModel
- .query()
- .insert({
- access_list_id: data.id,
- address: client.address,
- directive: client.directive
- })
- );
- }
- });
-
- const query = accessListClientModel
- .query()
- .delete()
- .where('access_list_id', data.id);
-
- return query
- .then(() => {
- // Add new items
- if (promises.length) {
- return Promise.all(promises);
- }
- });
- }
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'access-list',
- object_id: data.id,
- meta: internalAccessList.maskItems(data)
- });
- })
- .then(() => {
- // re-fetch with expansions
- return internalAccessList.get(access, {
- id: data.id,
- expand: ['owner', 'items', 'clients', 'proxy_hosts.[certificate,access_list.[clients,items]]']
- }, true /* <- skip masking */);
- })
- .then((row) => {
- return internalAccessList.build(row)
- .then(() => {
- if (parseInt(row.proxy_host_count, 10)) {
- return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
- }
- }).then(internalNginx.reload)
- .then(() => {
- return internalAccessList.maskItems(row);
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Integer} data.id
- * @param {Array} [data.expand]
- * @param {Array} [data.omit]
- * @param {Boolean} [skip_masking]
- * @return {Promise}
- */
- get: (access, data, skip_masking) => {
- if (typeof data === 'undefined') {
- data = {};
- }
-
- return access.can('access_lists:get', data.id)
- .then((access_data) => {
- const query = accessListModel
- .query()
- .select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
- .leftJoin('proxy_host', function() {
- this.on('proxy_host.access_list_id', '=', 'access_list.id')
- .andOn('proxy_host.is_deleted', '=', 0);
- })
- .where('access_list.is_deleted', 0)
- .andWhere('access_list.id', data.id)
- .groupBy('access_list.id')
- .allowGraph('[owner,items,clients,proxy_hosts.[certificate,access_list.[clients,items]]]')
- .first();
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('access_list.owner_user_id', access.token.getUserId(1));
- }
-
- if (typeof data.expand !== 'undefined' && data.expand !== null) {
- query.withGraphFetched(`[${data.expand.join(', ')}]`);
- }
-
- return query.then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
- if (!skip_masking && typeof row.items !== 'undefined' && row.items) {
- row = internalAccessList.maskItems(row);
- }
- // Custom omissions
- if (typeof data.omit !== 'undefined' && data.omit !== null) {
- row = _.omit(row, data.omit);
- }
- return row;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Integer} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- delete: (access, data) => {
- return access.can('access_lists:delete', data.id)
- .then(() => {
- return internalAccessList.get(access, {id: data.id, expand: ['proxy_hosts', 'items', 'clients']});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
-
- // 1. update row to be deleted
- // 2. update any proxy hosts that were using it (ignoring permissions)
- // 3. reconfigure those hosts
- // 4. audit log
-
- // 1. update row to be deleted
- return accessListModel
- .query()
- .where('id', row.id)
- .patch({
- is_deleted: 1
- })
- .then(() => {
- // 2. update any proxy hosts that were using it (ignoring permissions)
- if (row.proxy_hosts) {
- return proxyHostModel
- .query()
- .where('access_list_id', '=', row.id)
- .patch({access_list_id: 0})
- .then(() => {
- // 3. reconfigure those hosts, then reload nginx
-
- // set the access_list_id to zero for these items
- row.proxy_hosts.map((_val, idx) => {
- row.proxy_hosts[idx].access_list_id = 0;
- });
-
- return internalNginx.bulkGenerateConfigs('proxy_host', row.proxy_hosts);
- })
- .then(() => {
- return internalNginx.reload();
- });
- }
- })
- .then(() => {
- // delete the htpasswd file
- const htpasswd_file = internalAccessList.getFilename(row);
-
- try {
- fs.unlinkSync(htpasswd_file);
- } catch (_err) {
- // do nothing
- }
- })
- .then(() => {
- // 4. audit log
- return internalAuditLog.add(access, {
- action: 'deleted',
- object_type: 'access-list',
- object_id: row.id,
- meta: _.omit(internalAccessList.maskItems(row), ['is_deleted', 'proxy_hosts'])
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * All Lists
- *
- * @param {Access} access
- * @param {Array} [expand]
- * @param {String} [search_query]
- * @returns {Promise}
- */
- getAll: (access, expand, search_query) => {
- return access.can('access_lists:list')
- .then((access_data) => {
- const query = accessListModel
- .query()
- .select('access_list.*', accessListModel.raw('COUNT(proxy_host.id) as proxy_host_count'))
- .leftJoin('proxy_host', function() {
- this.on('proxy_host.access_list_id', '=', 'access_list.id')
- .andOn('proxy_host.is_deleted', '=', 0);
- })
- .where('access_list.is_deleted', 0)
- .groupBy('access_list.id')
- .allowGraph('[owner,items,clients]')
- .orderBy('access_list.name', 'ASC');
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('access_list.owner_user_id', access.token.getUserId(1));
- }
-
- // Query is used for searching
- if (typeof search_query === 'string') {
- query.where(function () {
- this.where('name', 'like', `%${search_query}%`);
- });
- }
-
- if (typeof expand !== 'undefined' && expand !== null) {
- query.withGraphFetched(`[${expand.join(', ')}]`);
- }
-
- return query.then(utils.omitRows(omissions()));
- })
- .then((rows) => {
- if (rows) {
- rows.map((row, idx) => {
- if (typeof row.items !== 'undefined' && row.items) {
- rows[idx] = internalAccessList.maskItems(row);
- }
- });
- }
-
- return rows;
- });
- },
-
- /**
- * Report use
- *
- * @param {Integer} user_id
- * @param {String} visibility
- * @returns {Promise}
- */
- getCount: (user_id, visibility) => {
- const query = accessListModel
- .query()
- .count('id as count')
- .where('is_deleted', 0);
-
- if (visibility !== 'all') {
- query.andWhere('owner_user_id', user_id);
- }
-
- return query.first()
- .then((row) => {
- return parseInt(row.count, 10);
- });
- },
-
- /**
- * @param {Object} list
- * @returns {Object}
- */
- maskItems: (list) => {
- if (list && typeof list.items !== 'undefined') {
- list.items.map((val, idx) => {
- let repeat_for = 8;
- let first_char = '*';
-
- if (typeof val.password !== 'undefined' && val.password) {
- repeat_for = val.password.length - 1;
- first_char = val.password.charAt(0);
- }
-
- list.items[idx].hint = first_char + ('*').repeat(repeat_for);
- list.items[idx].password = '';
- });
- }
-
- return list;
- },
-
- /**
- * @param {Object} list
- * @param {Integer} list.id
- * @returns {String}
- */
- getFilename: (list) => {
- return `/data/access/${list.id}`;
- },
-
- /**
- * @param {Object} list
- * @param {Integer} list.id
- * @param {String} list.name
- * @param {Array} list.items
- * @returns {Promise}
- */
- build: (list) => {
- logger.info(`Building Access file #${list.id} for: ${list.name}`);
-
- return new Promise((resolve, reject) => {
- const htpasswd_file = internalAccessList.getFilename(list);
-
- // 1. remove any existing access file
- try {
- fs.unlinkSync(htpasswd_file);
- } catch (_err) {
- // do nothing
- }
-
- // 2. create empty access file
- try {
- fs.writeFileSync(htpasswd_file, '', {encoding: 'utf8'});
- resolve(htpasswd_file);
- } catch (err) {
- reject(err);
- }
- })
- .then((htpasswd_file) => {
- // 3. generate password for each user
- if (list.items.length) {
- return new Promise((resolve, reject) => {
- batchflow(list.items).sequential()
- .each((_i, item, next) => {
- if (typeof item.password !== 'undefined' && item.password.length) {
- logger.info(`Adding: ${item.username}`);
-
- utils.execFile('openssl', ['passwd', '-apr1', item.password])
- .then((res) => {
- try {
- fs.appendFileSync(htpasswd_file, `${item.username}:${res}\n`, {encoding: 'utf8'});
- } catch (err) {
- reject(err);
- }
- next();
- })
- .catch((err) => {
- logger.error(err);
- next(err);
- });
- }
- })
- .error((err) => {
- logger.error(err);
- reject(err);
- })
- .end((results) => {
- logger.success(`Built Access file #${list.id} for: ${list.name}`);
- resolve(results);
- });
- });
- }
- });
- }
-};
-
-module.exports = internalAccessList;
diff --git a/backend/internal/audit-log.js b/backend/internal/audit-log.js
deleted file mode 100644
index 60bdd2ef..00000000
--- a/backend/internal/audit-log.js
+++ /dev/null
@@ -1,79 +0,0 @@
-const error = require('../lib/error');
-const auditLogModel = require('../models/audit-log');
-const {castJsonIfNeed} = require('../lib/helpers');
-
-const internalAuditLog = {
-
- /**
- * All logs
- *
- * @param {Access} access
- * @param {Array} [expand]
- * @param {String} [search_query]
- * @returns {Promise}
- */
- getAll: (access, expand, search_query) => {
- return access.can('auditlog:list')
- .then(() => {
- let query = auditLogModel
- .query()
- .orderBy('created_on', 'DESC')
- .orderBy('id', 'DESC')
- .limit(100)
- .allowGraph('[user]');
-
- // Query is used for searching
- if (typeof search_query === 'string' && search_query.length > 0) {
- query.where(function () {
- this.where(castJsonIfNeed('meta'), 'like', '%' + search_query + '%');
- });
- }
-
- if (typeof expand !== 'undefined' && expand !== null) {
- query.withGraphFetched('[' + expand.join(', ') + ']');
- }
-
- return query;
- });
- },
-
- /**
- * This method should not be publicly used, it doesn't check certain things. It will be assumed
- * that permission to add to audit log is already considered, however the access token is used for
- * default user id determination.
- *
- * @param {Access} access
- * @param {Object} data
- * @param {String} data.action
- * @param {Number} [data.user_id]
- * @param {Number} [data.object_id]
- * @param {Number} [data.object_type]
- * @param {Object} [data.meta]
- * @returns {Promise}
- */
- add: (access, data) => {
- return new Promise((resolve, reject) => {
- // Default the user id
- if (typeof data.user_id === 'undefined' || !data.user_id) {
- data.user_id = access.token.getUserId(1);
- }
-
- if (typeof data.action === 'undefined' || !data.action) {
- reject(new error.InternalValidationError('Audit log entry must contain an Action'));
- } else {
- // Make sure at least 1 of the IDs are set and action
- resolve(auditLogModel
- .query()
- .insert({
- user_id: data.user_id,
- action: data.action,
- object_type: data.object_type || '',
- object_id: data.object_id || 0,
- meta: data.meta || {}
- }));
- }
- });
- }
-};
-
-module.exports = internalAuditLog;
diff --git a/backend/internal/certificate.js b/backend/internal/certificate.js
deleted file mode 100644
index 55e74c3e..00000000
--- a/backend/internal/certificate.js
+++ /dev/null
@@ -1,1298 +0,0 @@
-const _ = require('lodash');
-const fs = require('node:fs');
-const https = require('node:https');
-const tempWrite = require('temp-write');
-const moment = require('moment');
-const archiver = require('archiver');
-const path = require('path');
-const { isArray } = require('lodash');
-const logger = require('../logger').ssl;
-const config = require('../lib/config');
-const error = require('../lib/error');
-const utils = require('../lib/utils');
-const certbot = require('../lib/certbot');
-const certificateModel = require('../models/certificate');
-const tokenModel = require('../models/token');
-const dnsPlugins = require('../global/certbot-dns-plugins.json');
-const internalAuditLog = require('./audit-log');
-const internalNginx = require('./nginx');
-const internalHost = require('./host');
-
-
-const letsencryptStaging = config.useLetsencryptStaging();
-const letsencryptServer = config.useLetsencryptServer();
-const letsencryptConfig = '/etc/letsencrypt.ini';
-const certbotCommand = 'certbot';
-
-function omissions() {
- return ['is_deleted', 'owner.is_deleted'];
-}
-
-const internalCertificate = {
-
- allowedSslFiles: ['certificate', 'certificate_key', 'intermediate_certificate'],
- intervalTimeout: 1000 * 60 * 60, // 1 hour
- interval: null,
- intervalProcessing: false,
- renewBeforeExpirationBy: [30, 'days'],
-
- initTimer: () => {
- logger.info('Let\'s Encrypt Renewal Timer initialized');
- internalCertificate.interval = setInterval(internalCertificate.processExpiringHosts, internalCertificate.intervalTimeout);
- // And do this now as well
- internalCertificate.processExpiringHosts();
- },
-
- /**
- * Triggered by a timer, this will check for expiring hosts and renew their ssl certs if required
- */
- processExpiringHosts: () => {
- if (!internalCertificate.intervalProcessing) {
- internalCertificate.intervalProcessing = true;
- logger.info(`Renewing SSL certs expiring within ${internalCertificate.renewBeforeExpirationBy[0]} ${internalCertificate.renewBeforeExpirationBy[1]} ...`);
-
- const expirationThreshold = moment().add(internalCertificate.renewBeforeExpirationBy[0], internalCertificate.renewBeforeExpirationBy[1]).format('YYYY-MM-DD HH:mm:ss');
-
- // Fetch all the letsencrypt certs from the db that will expire within the configured threshold
- certificateModel
- .query()
- .where('is_deleted', 0)
- .andWhere('provider', 'letsencrypt')
- .andWhere('expires_on', '<', expirationThreshold)
- .then((certificates) => {
- if (!certificates || !certificates.length) {
- return null;
- }
-
- /**
- * Renews must be run sequentially or we'll get an error 'Another
- * instance of Certbot is already running.'
- */
- let sequence = Promise.resolve();
-
- certificates.forEach((certificate) => {
- sequence = sequence.then(() =>
- internalCertificate
- .renew(
- {
- can: () =>
- Promise.resolve({
- permission_visibility: 'all',
- }),
- token: new tokenModel(),
- },
- { id: certificate.id },
- )
- .catch((err) => {
- // Don't want to stop the train here, just log the error
- logger.error(err.message);
- }),
- );
- });
-
- return sequence;
- })
- .then(() => {
- logger.info('Completed SSL cert renew process');
- internalCertificate.intervalProcessing = false;
- })
- .catch((err) => {
- logger.error(err);
- internalCertificate.intervalProcessing = false;
- });
- }
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @returns {Promise}
- */
- create: (access, data) => {
- return access.can('certificates:create', data)
- .then(() => {
- data.owner_user_id = access.token.getUserId(1);
-
- if (data.provider === 'letsencrypt') {
- data.nice_name = data.domain_names.join(', ');
- }
-
- return certificateModel
- .query()
- .insertAndFetch(data)
- .then(utils.omitRow(omissions()));
- })
- .then((certificate) => {
- if (certificate.provider === 'letsencrypt') {
- // Request a new Cert from LE. Let the fun begin.
-
- // 1. Find out any hosts that are using any of the hostnames in this cert
- // 2. Disable them in nginx temporarily
- // 3. Generate the LE config
- // 4. Request cert
- // 5. Remove LE config
- // 6. Re-instate previously disabled hosts
-
- // 1. Find out any hosts that are using any of the hostnames in this cert
- return internalHost.getHostsWithDomains(certificate.domain_names)
- .then((in_use_result) => {
- // 2. Disable them in nginx temporarily
- return internalCertificate.disableInUseHosts(in_use_result)
- .then(() => {
- return in_use_result;
- });
- })
- .then((in_use_result) => {
- // With DNS challenge no config is needed, so skip 3 and 5.
- if (certificate.meta.dns_challenge) {
- return internalNginx.reload().then(() => {
- // 4. Request cert
- return internalCertificate.requestLetsEncryptSslWithDnsChallenge(certificate);
- })
- .then(internalNginx.reload)
- .then(() => {
- // 6. Re-instate previously disabled hosts
- return internalCertificate.enableInUseHosts(in_use_result);
- })
- .then(() => {
- return certificate;
- })
- .catch((err) => {
- // In the event of failure, revert things and throw err back
- return internalCertificate.enableInUseHosts(in_use_result)
- .then(internalNginx.reload)
- .then(() => {
- throw err;
- });
- });
- } else {
- // 3. Generate the LE config
- return internalNginx.generateLetsEncryptRequestConfig(certificate)
- .then(internalNginx.reload)
- .then(async() => await new Promise((r) => setTimeout(r, 5000)))
- .then(() => {
- // 4. Request cert
- return internalCertificate.requestLetsEncryptSsl(certificate);
- })
- .then(() => {
- // 5. Remove LE config
- return internalNginx.deleteLetsEncryptRequestConfig(certificate);
- })
- .then(internalNginx.reload)
- .then(() => {
- // 6. Re-instate previously disabled hosts
- return internalCertificate.enableInUseHosts(in_use_result);
- })
- .then(() => {
- return certificate;
- })
- .catch((err) => {
- // In the event of failure, revert things and throw err back
- return internalNginx.deleteLetsEncryptRequestConfig(certificate)
- .then(() => {
- return internalCertificate.enableInUseHosts(in_use_result);
- })
- .then(internalNginx.reload)
- .then(() => {
- throw err;
- });
- });
- }
- })
- .then(() => {
- // At this point, the letsencrypt cert should exist on disk.
- // Lets get the expiry date from the file and update the row silently
- return internalCertificate.getCertificateInfoFromFile(`${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`)
- .then((cert_info) => {
- return certificateModel
- .query()
- .patchAndFetchById(certificate.id, {
- expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
- })
- .then(utils.omitRow(omissions()))
- .then((saved_row) => {
- // Add cert data for audit log
- saved_row.meta = _.assign({}, saved_row.meta, {
- letsencrypt_certificate: cert_info
- });
-
- return saved_row;
- });
- });
- }).catch(async (error) => {
- // Delete the certificate from the database if it was not created successfully
- await certificateModel
- .query()
- .deleteById(certificate.id);
-
- throw error;
- });
- } else {
- return certificate;
- }
- }).then((certificate) => {
-
- data.meta = _.assign({}, data.meta || {}, certificate.meta);
-
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'created',
- object_type: 'certificate',
- object_id: certificate.id,
- meta: data
- })
- .then(() => {
- return certificate;
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.email]
- * @param {String} [data.name]
- * @return {Promise}
- */
- update: (access, data) => {
- return access.can('certificates:update', data.id)
- .then((/*access_data*/) => {
- return internalCertificate.get(access, {id: data.id});
- })
- .then((row) => {
- if (row.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError(`Certificate could not be updated, IDs do not match: ${row.id} !== ${data.id}`);
- }
-
- return certificateModel
- .query()
- .patchAndFetchById(row.id, data)
- .then(utils.omitRow(omissions()))
- .then((saved_row) => {
- saved_row.meta = internalCertificate.cleanMeta(saved_row.meta);
- data.meta = internalCertificate.cleanMeta(data.meta);
-
- // Add row.nice_name for custom certs
- if (saved_row.provider === 'other') {
- data.nice_name = saved_row.nice_name;
- }
-
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'certificate',
- object_id: row.id,
- meta: _.omit(data, ['expires_on']) // this prevents json circular reference because expires_on might be raw
- })
- .then(() => {
- return saved_row;
- });
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {Array} [data.expand]
- * @param {Array} [data.omit]
- * @return {Promise}
- */
- get: (access, data) => {
- if (typeof data === 'undefined') {
- data = {};
- }
-
- return access.can('certificates:get', data.id)
- .then((access_data) => {
- const query = certificateModel
- .query()
- .where('is_deleted', 0)
- .andWhere('id', data.id)
- .allowGraph('[owner]')
- .allowGraph('[proxy_hosts]')
- .allowGraph('[redirection_hosts]')
- .allowGraph('[dead_hosts]')
- .first();
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- if (typeof data.expand !== 'undefined' && data.expand !== null) {
- query.withGraphFetched(`[${data.expand.join(', ')}]`);
- }
-
- return query.then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
- // Custom omissions
- if (typeof data.omit !== 'undefined' && data.omit !== null) {
- row = _.omit(row, data.omit);
- }
- return row;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @returns {Promise}
- */
- download: (access, data) => {
- return new Promise((resolve, reject) => {
- access.can('certificates:get', data)
- .then(() => {
- return internalCertificate.get(access, data);
- })
- .then((certificate) => {
- if (certificate.provider === 'letsencrypt') {
- const zipDirectory = internalCertificate.getLiveCertPath(data.id);
-
- if (!fs.existsSync(zipDirectory)) {
- throw new error.ItemNotFoundError(`Certificate ${certificate.nice_name} does not exists`);
- }
-
- const certFiles = fs.readdirSync(zipDirectory)
- .filter((fn) => fn.endsWith('.pem'))
- .map((fn) => fs.realpathSync(path.join(zipDirectory, fn)));
- const downloadName = `npm-${data.id}-${Date.now()}.zip`;
- const opName = `/tmp/${downloadName}`;
- internalCertificate.zipFiles(certFiles, opName)
- .then(() => {
- logger.debug('zip completed : ', opName);
- const resp = {
- fileName: opName
- };
- resolve(resp);
- }).catch((err) => reject(err));
- } else {
- throw new error.ValidationError('Only Let\'sEncrypt certificates can be downloaded');
- }
- }).catch((err) => reject(err));
- });
- },
-
- /**
- * @param {String} source
- * @param {String} out
- * @returns {Promise}
- */
- zipFiles(source, out) {
- const archive = archiver('zip', { zlib: { level: 9 } });
- const stream = fs.createWriteStream(out);
-
- return new Promise((resolve, reject) => {
- source
- .map((fl) => {
- const fileName = path.basename(fl);
- logger.debug(fl, 'added to certificate zip');
- archive.file(fl, { name: fileName });
- });
- archive
- .on('error', (err) => reject(err))
- .pipe(stream);
-
- stream.on('close', () => resolve());
- archive.finalize();
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- delete: (access, data) => {
- return access.can('certificates:delete', data.id)
- .then(() => {
- return internalCertificate.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
-
- return certificateModel
- .query()
- .where('id', row.id)
- .patch({
- is_deleted: 1
- })
- .then(() => {
- // Add to audit log
- row.meta = internalCertificate.cleanMeta(row.meta);
-
- return internalAuditLog.add(access, {
- action: 'deleted',
- object_type: 'certificate',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- })
- .then(() => {
- if (row.provider === 'letsencrypt') {
- // Revoke the cert
- return internalCertificate.revokeLetsEncryptSsl(row);
- }
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * All Certs
- *
- * @param {Access} access
- * @param {Array} [expand]
- * @param {String} [search_query]
- * @returns {Promise}
- */
- getAll: (access, expand, search_query) => {
- return access.can('certificates:list')
- .then((access_data) => {
- const query = certificateModel
- .query()
- .where('is_deleted', 0)
- .groupBy('id')
- .allowGraph('[owner]')
- .allowGraph('[proxy_hosts]')
- .allowGraph('[redirection_hosts]')
- .allowGraph('[dead_hosts]')
- .orderBy('nice_name', 'ASC');
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- // Query is used for searching
- if (typeof search_query === 'string') {
- query.where(function () {
- this.where('nice_name', 'like', `%${search_query}%`);
- });
- }
-
- if (typeof expand !== 'undefined' && expand !== null) {
- query.withGraphFetched(`[${expand.join(', ')}]`);
- }
-
- return query.then(utils.omitRows(omissions()));
- });
- },
-
- /**
- * Report use
- *
- * @param {Number} user_id
- * @param {String} visibility
- * @returns {Promise}
- */
- getCount: (user_id, visibility) => {
- const query = certificateModel
- .query()
- .count('id as count')
- .where('is_deleted', 0);
-
- if (visibility !== 'all') {
- query.andWhere('owner_user_id', user_id);
- }
-
- return query.first()
- .then((row) => {
- return parseInt(row.count, 10);
- });
- },
-
- /**
- * @param {Object} certificate
- * @returns {Promise}
- */
- writeCustomCert: (certificate) => {
- logger.info('Writing Custom Certificate:', certificate);
-
- const dir = `/data/custom_ssl/npm-${certificate.id}`;
-
- return new Promise((resolve, reject) => {
- if (certificate.provider === 'letsencrypt') {
- reject(new Error('Refusing to write letsencrypt certs here'));
- return;
- }
-
- let certData = certificate.meta.certificate;
- if (typeof certificate.meta.intermediate_certificate !== 'undefined') {
- certData = `${certData}\n${certificate.meta.intermediate_certificate}`;
- }
-
- try {
- if (!fs.existsSync(dir)) {
- fs.mkdirSync(dir);
- }
- } catch (err) {
- reject(err);
- return;
- }
-
- fs.writeFile(`${dir}/fullchain.pem`, certData, (err) => {
- if (err) {
- reject(err);
- } else {
- resolve();
- }
- });
- })
- .then(() => {
- return new Promise((resolve, reject) => {
- fs.writeFile(`${dir}/privkey.pem`, certificate.meta.certificate_key, (err) => {
- if (err) {
- reject(err);
- } else {
- resolve();
- }
- });
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Array} data.domain_names
- * @param {String} data.meta.letsencrypt_email
- * @param {Boolean} data.meta.letsencrypt_agree
- * @returns {Promise}
- */
- createQuickCertificate: (access, data) => {
- return internalCertificate.create(access, {
- provider: 'letsencrypt',
- domain_names: data.domain_names,
- meta: data.meta
- });
- },
-
- /**
- * Validates that the certs provided are good.
- * No access required here, nothing is changed or stored.
- *
- * @param {Object} data
- * @param {Object} data.files
- * @returns {Promise}
- */
- validate: (data) => {
- return new Promise((resolve) => {
- // Put file contents into an object
- const files = {};
- _.map(data.files, (file, name) => {
- if (internalCertificate.allowedSslFiles.indexOf(name) !== -1) {
- files[name] = file.data.toString();
- }
- });
-
- resolve(files);
- })
- .then((files) => {
- // For each file, create a temp file and write the contents to it
- // Then test it depending on the file type
- const promises = [];
- _.map(files, (content, type) => {
- promises.push(new Promise((resolve) => {
- if (type === 'certificate_key') {
- resolve(internalCertificate.checkPrivateKey(content));
- } else {
- // this should handle `certificate` and intermediate certificate
- resolve(internalCertificate.getCertificateInfo(content, true));
- }
- }).then((res) => {
- return {[type]: res};
- }));
- });
-
- return Promise.all(promises)
- .then((files) => {
- let data = {};
-
- _.each(files, (file) => {
- data = _.assign({}, data, file);
- });
-
- return data;
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {Object} data.files
- * @returns {Promise}
- */
- upload: (access, data) => {
- return internalCertificate.get(access, {id: data.id})
- .then((row) => {
- if (row.provider !== 'other') {
- throw new error.ValidationError('Cannot upload certificates for this type of provider');
- }
-
- return internalCertificate.validate(data)
- .then((validations) => {
- if (typeof validations.certificate === 'undefined') {
- throw new error.ValidationError('Certificate file was not provided');
- }
-
- _.map(data.files, (file, name) => {
- if (internalCertificate.allowedSslFiles.indexOf(name) !== -1) {
- row.meta[name] = file.data.toString();
- }
- });
-
- // TODO: This uses a mysql only raw function that won't translate to postgres
- return internalCertificate.update(access, {
- id: data.id,
- expires_on: moment(validations.certificate.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss'),
- domain_names: [validations.certificate.cn],
- meta: _.clone(row.meta) // Prevent the update method from changing this value that we'll use later
- })
- .then((certificate) => {
- certificate.meta = row.meta;
- return internalCertificate.writeCustomCert(certificate);
- });
- })
- .then(() => {
- return _.pick(row.meta, internalCertificate.allowedSslFiles);
- });
- });
- },
-
- /**
- * Uses the openssl command to validate the private key.
- * It will save the file to disk first, then run commands on it, then delete the file.
- *
- * @param {String} private_key This is the entire key contents as a string
- */
- checkPrivateKey: (private_key) => {
- return tempWrite(private_key, '/tmp')
- .then((filepath) => {
- return new Promise((resolve, reject) => {
- const failTimeout = setTimeout(() => {
- reject(new error.ValidationError('Result Validation Error: Validation timed out. This could be due to the key being passphrase-protected.'));
- }, 10000);
- utils
- .exec(`openssl pkey -in ${filepath} -check -noout 2>&1 `)
- .then((result) => {
- clearTimeout(failTimeout);
- if (!result.toLowerCase().includes('key is valid')) {
- reject(new error.ValidationError(`Result Validation Error: ${result}`));
- }
- fs.unlinkSync(filepath);
- resolve(true);
- })
- .catch((err) => {
- clearTimeout(failTimeout);
- fs.unlinkSync(filepath);
- reject(new error.ValidationError(`Certificate Key is not valid (${err.message})`, err));
- });
- });
- });
- },
-
- /**
- * Uses the openssl command to both validate and get info out of the certificate.
- * It will save the file to disk first, then run commands on it, then delete the file.
- *
- * @param {String} certificate This is the entire cert contents as a string
- * @param {Boolean} [throw_expired] Throw when the certificate is out of date
- */
- getCertificateInfo: (certificate, throw_expired) => {
- return tempWrite(certificate, '/tmp')
- .then((filepath) => {
- return internalCertificate.getCertificateInfoFromFile(filepath, throw_expired)
- .then((certData) => {
- fs.unlinkSync(filepath);
- return certData;
- }).catch((err) => {
- fs.unlinkSync(filepath);
- throw err;
- });
- });
- },
-
- /**
- * Uses the openssl command to both validate and get info out of the certificate.
- * It will save the file to disk first, then run commands on it, then delete the file.
- *
- * @param {String} certificate_file The file location on disk
- * @param {Boolean} [throw_expired] Throw when the certificate is out of date
- */
- getCertificateInfoFromFile: (certificate_file, throw_expired) => {
- const certData = {};
-
- return utils.execFile('openssl', ['x509', '-in', certificate_file, '-subject', '-noout'])
- .then((result) => {
- // Examples:
- // subject=CN = *.jc21.com
- // subject=CN = something.example.com
- const regex = /(?:subject=)?[^=]+=\s+(\S+)/gim;
- const match = regex.exec(result);
- if (match && typeof match[1] !== 'undefined') {
- certData.cn = match[1];
- }
- })
- .then(() => {
- return utils.execFile('openssl', ['x509', '-in', certificate_file, '-issuer', '-noout']);
- })
-
- .then((result) => {
- // Examples:
- // issuer=C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
- // issuer=C = US, O = Let's Encrypt, CN = E5
- // issuer=O = NginxProxyManager, CN = NginxProxyManager Intermediate CA","O = NginxProxyManager, CN = NginxProxyManager Intermediate CA
- const regex = /^(?:issuer=)?(.*)$/gim;
- const match = regex.exec(result);
- if (match && typeof match[1] !== 'undefined') {
- certData.issuer = match[1];
- }
- })
- .then(() => {
- return utils.execFile('openssl', ['x509', '-in', certificate_file, '-dates', '-noout']);
- })
- .then((result) => {
- // notBefore=Jul 14 04:04:29 2018 GMT
- // notAfter=Oct 12 04:04:29 2018 GMT
- let validFrom = null;
- let validTo = null;
-
- const lines = result.split('\n');
- lines.map((str) => {
- const regex = /^(\S+)=(.*)$/gim;
- const match = regex.exec(str.trim());
-
- if (match && typeof match[2] !== 'undefined') {
- const date = parseInt(moment(match[2], 'MMM DD HH:mm:ss YYYY z').format('X'), 10);
-
- if (match[1].toLowerCase() === 'notbefore') {
- validFrom = date;
- } else if (match[1].toLowerCase() === 'notafter') {
- validTo = date;
- }
- }
- });
-
- if (!validFrom || !validTo) {
- throw new error.ValidationError(`Could not determine dates from certificate: ${result}`);
- }
-
- if (throw_expired && validTo < parseInt(moment().format('X'), 10)) {
- throw new error.ValidationError('Certificate has expired');
- }
-
- certData.dates = {
- from: validFrom,
- to: validTo
- };
-
- return certData;
- }).catch((err) => {
- throw new error.ValidationError(`Certificate is not valid (${err.message})`, err);
- });
- },
-
- /**
- * Cleans the ssl keys from the meta object and sets them to "true"
- *
- * @param {Object} meta
- * @param {Boolean} [remove]
- * @returns {Object}
- */
- cleanMeta: (meta, remove) => {
- internalCertificate.allowedSslFiles.map((key) => {
- if (typeof meta[key] !== 'undefined' && meta[key]) {
- if (remove) {
- delete meta[key];
- } else {
- meta[key] = true;
- }
- }
- });
-
- return meta;
- },
-
- /**
- * Request a certificate using the http challenge
- * @param {Object} certificate the certificate row
- * @returns {Promise}
- */
- requestLetsEncryptSsl: (certificate) => {
- logger.info(`Requesting LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
-
- const args = [
- 'certonly',
- '--config',
- letsencryptConfig,
- '--work-dir',
- '/tmp/letsencrypt-lib',
- '--logs-dir',
- '/tmp/letsencrypt-log',
- '--cert-name',
- `npm-${certificate.id}`,
- '--agree-tos',
- '--authenticator',
- 'webroot',
- '--email',
- certificate.meta.letsencrypt_email,
- '--preferred-challenges',
- 'dns,http',
- '--domains',
- certificate.domain_names.join(','),
- ];
-
- const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id);
- args.push(...adds.args);
-
- logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
-
- return utils.execFile(certbotCommand, args, adds.opts)
- .then((result) => {
- logger.success(result);
- return result;
- });
- },
-
- /**
- * @param {Object} certificate the certificate row
- * @param {String} dns_provider the dns provider name (key used in `certbot-dns-plugins.json`)
- * @param {String | null} credentials the content of this providers credentials file
- * @param {String} propagation_seconds
- * @returns {Promise}
- */
- requestLetsEncryptSslWithDnsChallenge: async (certificate) => {
- await certbot.installPlugin(certificate.meta.dns_provider);
- const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
- logger.info(`Requesting LetsEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
-
- const credentialsLocation = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
- fs.mkdirSync('/etc/letsencrypt/credentials', { recursive: true });
- fs.writeFileSync(credentialsLocation, certificate.meta.dns_provider_credentials, {mode: 0o600});
-
- // Whether the plugin has a ---credentials argument
- const hasConfigArg = certificate.meta.dns_provider !== 'route53';
-
- const args = [
- 'certonly',
- '--config',
- letsencryptConfig,
- '--work-dir',
- '/tmp/letsencrypt-lib',
- '--logs-dir',
- '/tmp/letsencrypt-log',
- '--cert-name',
- `npm-${certificate.id}`,
- '--agree-tos',
- '--email',
- certificate.meta.letsencrypt_email,
- '--domains',
- certificate.domain_names.join(','),
- '--authenticator',
- dnsPlugin.full_plugin_name,
- ];
-
- if (hasConfigArg) {
- args.push(`--${dnsPlugin.full_plugin_name}-credentials`, credentialsLocation);
- }
- if (certificate.meta.propagation_seconds !== undefined) {
- args.push(`--${dnsPlugin.full_plugin_name}-propagation-seconds`, certificate.meta.propagation_seconds.toString());
- }
-
- const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
- args.push(...adds.args);
-
- logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
-
- try {
- const result = await utils.execFile(certbotCommand, args, adds.opts);
- logger.info(result);
- return result;
- } catch (err) {
- // Don't fail if file does not exist, so no need for action in the callback
- fs.unlink(credentialsLocation, () => {});
- throw err;
- }
- },
-
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @returns {Promise}
- */
- renew: (access, data) => {
- return access.can('certificates:update', data)
- .then(() => {
- return internalCertificate.get(access, data);
- })
- .then((certificate) => {
- if (certificate.provider === 'letsencrypt') {
- const renewMethod = certificate.meta.dns_challenge ? internalCertificate.renewLetsEncryptSslWithDnsChallenge : internalCertificate.renewLetsEncryptSsl;
-
- return renewMethod(certificate)
- .then(() => {
- return internalCertificate.getCertificateInfoFromFile(`${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`);
- })
- .then((cert_info) => {
- return certificateModel
- .query()
- .patchAndFetchById(certificate.id, {
- expires_on: moment(cert_info.dates.to, 'X').format('YYYY-MM-DD HH:mm:ss')
- });
- })
- .then((updated_certificate) => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'renewed',
- object_type: 'certificate',
- object_id: updated_certificate.id,
- meta: updated_certificate
- })
- .then(() => {
- return updated_certificate;
- });
- });
- } else {
- throw new error.ValidationError('Only Let\'sEncrypt certificates can be renewed');
- }
- });
- },
-
- /**
- * @param {Object} certificate the certificate row
- * @returns {Promise}
- */
- renewLetsEncryptSsl: (certificate) => {
- logger.info(`Renewing LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
-
- const args = [
- 'renew',
- '--force-renewal',
- '--config',
- letsencryptConfig,
- '--work-dir',
- '/tmp/letsencrypt-lib',
- '--logs-dir',
- '/tmp/letsencrypt-log',
- '--cert-name',
- `npm-${certificate.id}`,
- '--preferred-challenges',
- 'dns,http',
- '--no-random-sleep-on-renew',
- '--disable-hook-validation',
- ];
-
- const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
- args.push(...adds.args);
-
- logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
-
- return utils.execFile(certbotCommand, args, adds.opts)
- .then((result) => {
- logger.info(result);
- return result;
- });
- },
-
- /**
- * @param {Object} certificate the certificate row
- * @returns {Promise}
- */
- renewLetsEncryptSslWithDnsChallenge: (certificate) => {
- const dnsPlugin = dnsPlugins[certificate.meta.dns_provider];
-
- if (!dnsPlugin) {
- throw Error(`Unknown DNS provider '${certificate.meta.dns_provider}'`);
- }
-
- logger.info(`Renewing LetsEncrypt certificates via ${dnsPlugin.name} for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
-
- const args = [
- 'renew',
- '--force-renewal',
- '--config',
- letsencryptConfig,
- '--work-dir',
- '/tmp/letsencrypt-lib',
- '--logs-dir',
- '/tmp/letsencrypt-log',
- '--cert-name',
- `npm-${certificate.id}`,
- '--disable-hook-validation',
- '--no-random-sleep-on-renew',
- ];
-
- const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id, certificate.meta.dns_provider);
- args.push(...adds.args);
-
- logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
-
- return utils.execFile(certbotCommand, args, adds.opts)
- .then(async (result) => {
- logger.info(result);
- return result;
- });
- },
-
- /**
- * @param {Object} certificate the certificate row
- * @param {Boolean} [throw_errors]
- * @returns {Promise}
- */
- revokeLetsEncryptSsl: (certificate, throw_errors) => {
- logger.info(`Revoking LetsEncrypt certificates for Cert #${certificate.id}: ${certificate.domain_names.join(', ')}`);
-
- const args = [
- 'revoke',
- '--config',
- letsencryptConfig,
- '--work-dir',
- '/tmp/letsencrypt-lib',
- '--logs-dir',
- '/tmp/letsencrypt-log',
- '--cert-path',
- `${internalCertificate.getLiveCertPath(certificate.id)}/fullchain.pem`,
- '--delete-after-revoke',
- ];
-
- const adds = internalCertificate.getAdditionalCertbotArgs(certificate.id);
- args.push(...adds.args);
-
- logger.info(`Command: ${certbotCommand} ${args ? args.join(' ') : ''}`);
-
- return utils.execFile(certbotCommand, args, adds.opts)
- .then(async (result) => {
- await utils.exec(`rm -f '/etc/letsencrypt/credentials/credentials-${certificate.id}' || true`);
- logger.info(result);
- return result;
- })
- .catch((err) => {
- logger.error(err.message);
-
- if (throw_errors) {
- throw err;
- }
- });
- },
-
- /**
- * @param {Object} certificate
- * @returns {Boolean}
- */
- hasLetsEncryptSslCerts: (certificate) => {
- const letsencryptPath = internalCertificate.getLiveCertPath(certificate.id);
- return fs.existsSync(`${letsencryptPath}/fullchain.pem`) && fs.existsSync(`${letsencryptPath}/privkey.pem`);
- },
-
- /**
- * @param {Object} in_use_result
- * @param {Number} in_use_result.total_count
- * @param {Array} in_use_result.proxy_hosts
- * @param {Array} in_use_result.redirection_hosts
- * @param {Array} in_use_result.dead_hosts
- */
- disableInUseHosts: (in_use_result) => {
- if (in_use_result.total_count) {
- const promises = [];
-
- if (in_use_result.proxy_hosts.length) {
- promises.push(internalNginx.bulkDeleteConfigs('proxy_host', in_use_result.proxy_hosts));
- }
-
- if (in_use_result.redirection_hosts.length) {
- promises.push(internalNginx.bulkDeleteConfigs('redirection_host', in_use_result.redirection_hosts));
- }
-
- if (in_use_result.dead_hosts.length) {
- promises.push(internalNginx.bulkDeleteConfigs('dead_host', in_use_result.dead_hosts));
- }
-
- return Promise.all(promises);
-
- } else {
- return Promise.resolve();
- }
- },
-
- /**
- * @param {Object} in_use_result
- * @param {Number} in_use_result.total_count
- * @param {Array} in_use_result.proxy_hosts
- * @param {Array} in_use_result.redirection_hosts
- * @param {Array} in_use_result.dead_hosts
- */
- enableInUseHosts: (in_use_result) => {
- if (in_use_result.total_count) {
- const promises = [];
-
- if (in_use_result.proxy_hosts.length) {
- promises.push(internalNginx.bulkGenerateConfigs('proxy_host', in_use_result.proxy_hosts));
- }
-
- if (in_use_result.redirection_hosts.length) {
- promises.push(internalNginx.bulkGenerateConfigs('redirection_host', in_use_result.redirection_hosts));
- }
-
- if (in_use_result.dead_hosts.length) {
- promises.push(internalNginx.bulkGenerateConfigs('dead_host', in_use_result.dead_hosts));
- }
-
- return Promise.all(promises);
-
- } else {
- return Promise.resolve();
- }
- },
-
- testHttpsChallenge: async (access, domains) => {
- await access.can('certificates:list');
-
- if (!isArray(domains)) {
- throw new error.InternalValidationError('Domains must be an array of strings');
- }
- if (domains.length === 0) {
- throw new error.InternalValidationError('No domains provided');
- }
-
- // Create a test challenge file
- const testChallengeDir = '/data/letsencrypt-acme-challenge/.well-known/acme-challenge';
- const testChallengeFile = `${testChallengeDir}/test-challenge`;
- fs.mkdirSync(testChallengeDir, {recursive: true});
- fs.writeFileSync(testChallengeFile, 'Success', {encoding: 'utf8'});
-
- async function performTestForDomain (domain) {
- logger.info(`Testing http challenge for ${domain}`);
- const url = `http://${domain}/.well-known/acme-challenge/test-challenge`;
- const formBody = `method=G&url=${encodeURI(url)}&bodytype=T&requestbody=&headername=User-Agent&headervalue=None&locationid=1&ch=false&cc=false`;
- const options = {
- method: 'POST',
- headers: {
- 'User-Agent': 'Mozilla/5.0',
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'Content-Length': Buffer.byteLength(formBody)
- }
- };
-
- const result = await new Promise((resolve) => {
-
- const req = https.request('https://www.site24x7.com/tools/restapi-tester', options, (res) => {
- let responseBody = '';
-
- res.on('data', (chunk) => {
- responseBody = responseBody + chunk;
- });
-
- res.on('end', () => {
- try {
- const parsedBody = JSON.parse(`${responseBody}`);
- if (res.statusCode !== 200) {
- logger.warn(`Failed to test HTTP challenge for domain ${domain} because HTTP status code ${res.statusCode} was returned: ${parsedBody.message}`);
- resolve(undefined);
- } else {
- resolve(parsedBody);
- }
- } catch (err) {
- if (res.statusCode !== 200) {
- logger.warn(`Failed to test HTTP challenge for domain ${domain} because HTTP status code ${res.statusCode} was returned`);
- } else {
- logger.warn(`Failed to test HTTP challenge for domain ${domain} because response failed to be parsed: ${err.message}`);
- }
- resolve(undefined);
- }
- });
- });
-
- // Make sure to write the request body.
- req.write(formBody);
- req.end();
- req.on('error', (e) => { logger.warn(`Failed to test HTTP challenge for domain ${domain}`, e);
- resolve(undefined); });
- });
-
- if (!result) {
- // Some error occurred while trying to get the data
- return 'failed';
- } else if (result.error) {
- logger.info(`HTTP challenge test failed for domain ${domain} because error was returned: ${result.error.msg}`);
- return `other:${result.error.msg}`;
- } else if (`${result.responsecode}` === '200' && result.htmlresponse === 'Success') {
- // Server exists and has responded with the correct data
- return 'ok';
- } else if (`${result.responsecode}` === '200') {
- // Server exists but has responded with wrong data
- logger.info(`HTTP challenge test failed for domain ${domain} because of invalid returned data:`, result.htmlresponse);
- return 'wrong-data';
- } else if (`${result.responsecode}` === '404') {
- // Server exists but responded with a 404
- logger.info(`HTTP challenge test failed for domain ${domain} because code 404 was returned`);
- return '404';
- } else if (`${result.responsecode}` === '0' || (typeof result.reason === 'string' && result.reason.toLowerCase() === 'host unavailable')) {
- // Server does not exist at domain
- logger.info(`HTTP challenge test failed for domain ${domain} the host was not found`);
- return 'no-host';
- } else {
- // Other errors
- logger.info(`HTTP challenge test failed for domain ${domain} because code ${result.responsecode} was returned`);
- return `other:${result.responsecode}`;
- }
- }
-
- const results = {};
-
- for (const domain of domains){
- results[domain] = await performTestForDomain(domain);
- }
-
- // Remove the test challenge file
- fs.unlinkSync(testChallengeFile);
-
- return results;
- },
-
- getAdditionalCertbotArgs: (certificate_id, dns_provider) => {
- const args = [];
- if (letsencryptServer !== null) {
- args.push('--server', letsencryptServer);
- }
- if (letsencryptStaging && letsencryptServer === null) {
- args.push('--staging');
- }
-
- // For route53, add the credentials file as an environment variable,
- // inheriting the process env
- const opts = {};
- if (certificate_id && dns_provider === 'route53') {
- opts.env = process.env;
- opts.env.AWS_CONFIG_FILE = `/etc/letsencrypt/credentials/credentials-${certificate_id}`;
- }
-
- if (dns_provider === 'duckdns') {
- args.push('--dns-duckdns-no-txt-restore');
- }
-
- return {args: args, opts: opts};
- },
-
- getLiveCertPath: (certificate_id) => {
- return `/etc/letsencrypt/live/npm-${certificate_id}`;
- }
-};
-
-module.exports = internalCertificate;
diff --git a/backend/internal/dead-host.js b/backend/internal/dead-host.js
deleted file mode 100644
index 6bbdf61b..00000000
--- a/backend/internal/dead-host.js
+++ /dev/null
@@ -1,465 +0,0 @@
-const _ = require('lodash');
-const error = require('../lib/error');
-const utils = require('../lib/utils');
-const deadHostModel = require('../models/dead_host');
-const internalHost = require('./host');
-const internalNginx = require('./nginx');
-const internalAuditLog = require('./audit-log');
-const internalCertificate = require('./certificate');
-const {castJsonIfNeed} = require('../lib/helpers');
-
-function omissions () {
- return ['is_deleted'];
-}
-
-const internalDeadHost = {
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @returns {Promise}
- */
- create: (access, data) => {
- let create_certificate = data.certificate_id === 'new';
-
- if (create_certificate) {
- delete data.certificate_id;
- }
-
- return access.can('dead_hosts:create', data)
- .then((/*access_data*/) => {
- // Get a list of the domain names and check each of them against existing records
- let domain_name_check_promises = [];
-
- data.domain_names.map(function (domain_name) {
- domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name));
- });
-
- return Promise.all(domain_name_check_promises)
- .then((check_results) => {
- check_results.map(function (result) {
- if (result.is_taken) {
- throw new error.ValidationError(result.hostname + ' is already in use');
- }
- });
- });
- })
- .then(() => {
- // At this point the domains should have been checked
- data.owner_user_id = access.token.getUserId(1);
- data = internalHost.cleanSslHstsData(data);
-
- // Fix for db field not having a default value
- // for this optional field.
- if (typeof data.advanced_config === 'undefined') {
- data.advanced_config = '';
- }
-
- return deadHostModel
- .query()
- .insertAndFetch(data)
- .then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (create_certificate) {
- return internalCertificate.createQuickCertificate(access, data)
- .then((cert) => {
- // update host with cert id
- return internalDeadHost.update(access, {
- id: row.id,
- certificate_id: cert.id
- });
- })
- .then(() => {
- return row;
- });
- } else {
- return row;
- }
- })
- .then((row) => {
- // re-fetch with cert
- return internalDeadHost.get(access, {
- id: row.id,
- expand: ['certificate', 'owner']
- });
- })
- .then((row) => {
- // Configure nginx
- return internalNginx.configure(deadHostModel, 'dead_host', row)
- .then(() => {
- return row;
- });
- })
- .then((row) => {
- data.meta = _.assign({}, data.meta || {}, row.meta);
-
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'created',
- object_type: 'dead-host',
- object_id: row.id,
- meta: data
- })
- .then(() => {
- return row;
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @return {Promise}
- */
- update: (access, data) => {
- let create_certificate = data.certificate_id === 'new';
-
- if (create_certificate) {
- delete data.certificate_id;
- }
-
- return access.can('dead_hosts:update', data.id)
- .then((/*access_data*/) => {
- // Get a list of the domain names and check each of them against existing records
- let domain_name_check_promises = [];
-
- if (typeof data.domain_names !== 'undefined') {
- data.domain_names.map(function (domain_name) {
- domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name, 'dead', data.id));
- });
-
- return Promise.all(domain_name_check_promises)
- .then((check_results) => {
- check_results.map(function (result) {
- if (result.is_taken) {
- throw new error.ValidationError(result.hostname + ' is already in use');
- }
- });
- });
- }
- })
- .then(() => {
- return internalDeadHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (row.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError('404 Host could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
- }
-
- if (create_certificate) {
- return internalCertificate.createQuickCertificate(access, {
- domain_names: data.domain_names || row.domain_names,
- meta: _.assign({}, row.meta, data.meta)
- })
- .then((cert) => {
- // update host with cert id
- data.certificate_id = cert.id;
- })
- .then(() => {
- return row;
- });
- } else {
- return row;
- }
- })
- .then((row) => {
- // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
- data = _.assign({}, {
- domain_names: row.domain_names
- }, data);
-
- data = internalHost.cleanSslHstsData(data, row);
-
- return deadHostModel
- .query()
- .where({id: data.id})
- .patch(data)
- .then((saved_row) => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'dead-host',
- object_id: row.id,
- meta: data
- })
- .then(() => {
- return _.omit(saved_row, omissions());
- });
- });
- })
- .then(() => {
- return internalDeadHost.get(access, {
- id: data.id,
- expand: ['owner', 'certificate']
- })
- .then((row) => {
- // Configure nginx
- return internalNginx.configure(deadHostModel, 'dead_host', row)
- .then((new_meta) => {
- row.meta = new_meta;
- row = internalHost.cleanRowCertificateMeta(row);
- return _.omit(row, omissions());
- });
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {Array} [data.expand]
- * @param {Array} [data.omit]
- * @return {Promise}
- */
- get: (access, data) => {
- if (typeof data === 'undefined') {
- data = {};
- }
-
- return access.can('dead_hosts:get', data.id)
- .then((access_data) => {
- let query = deadHostModel
- .query()
- .where('is_deleted', 0)
- .andWhere('id', data.id)
- .allowGraph('[owner,certificate]')
- .first();
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- if (typeof data.expand !== 'undefined' && data.expand !== null) {
- query.withGraphFetched('[' + data.expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
- // Custom omissions
- if (typeof data.omit !== 'undefined' && data.omit !== null) {
- row = _.omit(row, data.omit);
- }
- return row;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- delete: (access, data) => {
- return access.can('dead_hosts:delete', data.id)
- .then(() => {
- return internalDeadHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
-
- return deadHostModel
- .query()
- .where('id', row.id)
- .patch({
- is_deleted: 1
- })
- .then(() => {
- // Delete Nginx Config
- return internalNginx.deleteConfig('dead_host', row)
- .then(() => {
- return internalNginx.reload();
- });
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'deleted',
- object_type: 'dead-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- enable: (access, data) => {
- return access.can('dead_hosts:update', data.id)
- .then(() => {
- return internalDeadHost.get(access, {
- id: data.id,
- expand: ['certificate', 'owner']
- });
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- } else if (row.enabled) {
- throw new error.ValidationError('Host is already enabled');
- }
-
- row.enabled = 1;
-
- return deadHostModel
- .query()
- .where('id', row.id)
- .patch({
- enabled: 1
- })
- .then(() => {
- // Configure nginx
- return internalNginx.configure(deadHostModel, 'dead_host', row);
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'enabled',
- object_type: 'dead-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- disable: (access, data) => {
- return access.can('dead_hosts:update', data.id)
- .then(() => {
- return internalDeadHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- } else if (!row.enabled) {
- throw new error.ValidationError('Host is already disabled');
- }
-
- row.enabled = 0;
-
- return deadHostModel
- .query()
- .where('id', row.id)
- .patch({
- enabled: 0
- })
- .then(() => {
- // Delete Nginx Config
- return internalNginx.deleteConfig('dead_host', row)
- .then(() => {
- return internalNginx.reload();
- });
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'disabled',
- object_type: 'dead-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * All Hosts
- *
- * @param {Access} access
- * @param {Array} [expand]
- * @param {String} [search_query]
- * @returns {Promise}
- */
- getAll: (access, expand, search_query) => {
- return access.can('dead_hosts:list')
- .then((access_data) => {
- let query = deadHostModel
- .query()
- .where('is_deleted', 0)
- .groupBy('id')
- .allowGraph('[owner,certificate]')
- .orderBy(castJsonIfNeed('domain_names'), 'ASC');
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- // Query is used for searching
- if (typeof search_query === 'string' && search_query.length > 0) {
- query.where(function () {
- this.where(castJsonIfNeed('domain_names'), 'like', '%' + search_query + '%');
- });
- }
-
- if (typeof expand !== 'undefined' && expand !== null) {
- query.withGraphFetched('[' + expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRows(omissions()));
- })
- .then((rows) => {
- if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
- return internalHost.cleanAllRowsCertificateMeta(rows);
- }
-
- return rows;
- });
- },
-
- /**
- * Report use
- *
- * @param {Number} user_id
- * @param {String} visibility
- * @returns {Promise}
- */
- getCount: (user_id, visibility) => {
- let query = deadHostModel
- .query()
- .count('id as count')
- .where('is_deleted', 0);
-
- if (visibility !== 'all') {
- query.andWhere('owner_user_id', user_id);
- }
-
- return query.first()
- .then((row) => {
- return parseInt(row.count, 10);
- });
- }
-};
-
-module.exports = internalDeadHost;
diff --git a/backend/internal/host.js b/backend/internal/host.js
deleted file mode 100644
index 52c6d2bd..00000000
--- a/backend/internal/host.js
+++ /dev/null
@@ -1,236 +0,0 @@
-const _ = require('lodash');
-const proxyHostModel = require('../models/proxy_host');
-const redirectionHostModel = require('../models/redirection_host');
-const deadHostModel = require('../models/dead_host');
-const {castJsonIfNeed} = require('../lib/helpers');
-
-const internalHost = {
-
- /**
- * Makes sure that the ssl_* and hsts_* fields play nicely together.
- * ie: if there is no cert, then force_ssl is off.
- * if force_ssl is off, then hsts_enabled is definitely off.
- *
- * @param {object} data
- * @param {object} [existing_data]
- * @returns {object}
- */
- cleanSslHstsData: function (data, existing_data) {
- existing_data = existing_data === undefined ? {} : existing_data;
-
- const combined_data = _.assign({}, existing_data, data);
-
- if (!combined_data.certificate_id) {
- combined_data.ssl_forced = false;
- combined_data.http2_support = false;
- }
-
- if (!combined_data.ssl_forced) {
- combined_data.hsts_enabled = false;
- }
-
- if (!combined_data.hsts_enabled) {
- combined_data.hsts_subdomains = false;
- }
-
- return combined_data;
- },
-
- /**
- * used by the getAll functions of hosts, this removes the certificate meta if present
- *
- * @param {Array} rows
- * @returns {Array}
- */
- cleanAllRowsCertificateMeta: function (rows) {
- rows.map(function (row, idx) {
- if (typeof rows[idx].certificate !== 'undefined' && rows[idx].certificate) {
- rows[idx].certificate.meta = {};
- }
- });
-
- return rows;
- },
-
- /**
- * used by the get/update functions of hosts, this removes the certificate meta if present
- *
- * @param {Object} row
- * @returns {Object}
- */
- cleanRowCertificateMeta: function (row) {
- if (typeof row.certificate !== 'undefined' && row.certificate) {
- row.certificate.meta = {};
- }
-
- return row;
- },
-
- /**
- * This returns all the host types with any domain listed in the provided domain_names array.
- * This is used by the certificates to temporarily disable any host that is using the domain
- *
- * @param {Array} domain_names
- * @returns {Promise}
- */
- getHostsWithDomains: function (domain_names) {
- const promises = [
- proxyHostModel
- .query()
- .where('is_deleted', 0),
- redirectionHostModel
- .query()
- .where('is_deleted', 0),
- deadHostModel
- .query()
- .where('is_deleted', 0)
- ];
-
- return Promise.all(promises)
- .then((promises_results) => {
- let response_object = {
- total_count: 0,
- dead_hosts: [],
- proxy_hosts: [],
- redirection_hosts: []
- };
-
- if (promises_results[0]) {
- // Proxy Hosts
- response_object.proxy_hosts = internalHost._getHostsWithDomains(promises_results[0], domain_names);
- response_object.total_count += response_object.proxy_hosts.length;
- }
-
- if (promises_results[1]) {
- // Redirection Hosts
- response_object.redirection_hosts = internalHost._getHostsWithDomains(promises_results[1], domain_names);
- response_object.total_count += response_object.redirection_hosts.length;
- }
-
- if (promises_results[2]) {
- // Dead Hosts
- response_object.dead_hosts = internalHost._getHostsWithDomains(promises_results[2], domain_names);
- response_object.total_count += response_object.dead_hosts.length;
- }
-
- return response_object;
- });
- },
-
- /**
- * Internal use only, checks to see if the domain is already taken by any other record
- *
- * @param {String} hostname
- * @param {String} [ignore_type] 'proxy', 'redirection', 'dead'
- * @param {Integer} [ignore_id] Must be supplied if type was also supplied
- * @returns {Promise}
- */
- isHostnameTaken: function (hostname, ignore_type, ignore_id) {
- const promises = [
- proxyHostModel
- .query()
- .where('is_deleted', 0)
- .andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%'),
- redirectionHostModel
- .query()
- .where('is_deleted', 0)
- .andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%'),
- deadHostModel
- .query()
- .where('is_deleted', 0)
- .andWhere(castJsonIfNeed('domain_names'), 'like', '%' + hostname + '%')
- ];
-
- return Promise.all(promises)
- .then((promises_results) => {
- let is_taken = false;
-
- if (promises_results[0]) {
- // Proxy Hosts
- if (internalHost._checkHostnameRecordsTaken(hostname, promises_results[0], ignore_type === 'proxy' && ignore_id ? ignore_id : 0)) {
- is_taken = true;
- }
- }
-
- if (promises_results[1]) {
- // Redirection Hosts
- if (internalHost._checkHostnameRecordsTaken(hostname, promises_results[1], ignore_type === 'redirection' && ignore_id ? ignore_id : 0)) {
- is_taken = true;
- }
- }
-
- if (promises_results[2]) {
- // Dead Hosts
- if (internalHost._checkHostnameRecordsTaken(hostname, promises_results[2], ignore_type === 'dead' && ignore_id ? ignore_id : 0)) {
- is_taken = true;
- }
- }
-
- return {
- hostname: hostname,
- is_taken: is_taken
- };
- });
- },
-
- /**
- * Private call only
- *
- * @param {String} hostname
- * @param {Array} existing_rows
- * @param {Integer} [ignore_id]
- * @returns {Boolean}
- */
- _checkHostnameRecordsTaken: function (hostname, existing_rows, ignore_id) {
- let is_taken = false;
-
- if (existing_rows && existing_rows.length) {
- existing_rows.map(function (existing_row) {
- existing_row.domain_names.map(function (existing_hostname) {
- // Does this domain match?
- if (existing_hostname.toLowerCase() === hostname.toLowerCase()) {
- if (!ignore_id || ignore_id !== existing_row.id) {
- is_taken = true;
- }
- }
- });
- });
- }
-
- return is_taken;
- },
-
- /**
- * Private call only
- *
- * @param {Array} hosts
- * @param {Array} domain_names
- * @returns {Array}
- */
- _getHostsWithDomains: function (hosts, domain_names) {
- let response = [];
-
- if (hosts && hosts.length) {
- hosts.map(function (host) {
- let host_matches = false;
-
- domain_names.map(function (domain_name) {
- host.domain_names.map(function (host_domain_name) {
- if (domain_name.toLowerCase() === host_domain_name.toLowerCase()) {
- host_matches = true;
- }
- });
- });
-
- if (host_matches) {
- response.push(host);
- }
- });
- }
-
- return response;
- }
-
-};
-
-module.exports = internalHost;
diff --git a/backend/internal/ip_ranges.js b/backend/internal/ip_ranges.js
deleted file mode 100644
index d34ee5a1..00000000
--- a/backend/internal/ip_ranges.js
+++ /dev/null
@@ -1,147 +0,0 @@
-const https = require('https');
-const fs = require('fs');
-const logger = require('../logger').ip_ranges;
-const error = require('../lib/error');
-const utils = require('../lib/utils');
-const internalNginx = require('./nginx');
-
-const CLOUDFRONT_URL = 'https://ip-ranges.amazonaws.com/ip-ranges.json';
-const CLOUDFARE_V4_URL = 'https://www.cloudflare.com/ips-v4';
-const CLOUDFARE_V6_URL = 'https://www.cloudflare.com/ips-v6';
-
-const regIpV4 = /^(\d+\.?){4}\/\d+/;
-const regIpV6 = /^(([\da-fA-F]+)?:)+\/\d+/;
-
-const internalIpRanges = {
-
- interval_timeout: 1000 * 60 * 60 * 6, // 6 hours
- interval: null,
- interval_processing: false,
- iteration_count: 0,
-
- initTimer: () => {
- logger.info('IP Ranges Renewal Timer initialized');
- internalIpRanges.interval = setInterval(internalIpRanges.fetch, internalIpRanges.interval_timeout);
- },
-
- fetchUrl: (url) => {
- return new Promise((resolve, reject) => {
- logger.info('Fetching ' + url);
- return https.get(url, (res) => {
- res.setEncoding('utf8');
- let raw_data = '';
- res.on('data', (chunk) => {
- raw_data += chunk;
- });
-
- res.on('end', () => {
- resolve(raw_data);
- });
- }).on('error', (err) => {
- reject(err);
- });
- });
- },
-
- /**
- * Triggered at startup and then later by a timer, this will fetch the ip ranges from services and apply them to nginx.
- */
- fetch: () => {
- if (!internalIpRanges.interval_processing) {
- internalIpRanges.interval_processing = true;
- logger.info('Fetching IP Ranges from online services...');
-
- let ip_ranges = [];
-
- return internalIpRanges.fetchUrl(CLOUDFRONT_URL)
- .then((cloudfront_data) => {
- let data = JSON.parse(cloudfront_data);
-
- if (data && typeof data.prefixes !== 'undefined') {
- data.prefixes.map((item) => {
- if (item.service === 'CLOUDFRONT') {
- ip_ranges.push(item.ip_prefix);
- }
- });
- }
-
- if (data && typeof data.ipv6_prefixes !== 'undefined') {
- data.ipv6_prefixes.map((item) => {
- if (item.service === 'CLOUDFRONT') {
- ip_ranges.push(item.ipv6_prefix);
- }
- });
- }
- })
- .then(() => {
- return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
- })
- .then((cloudfare_data) => {
- let items = cloudfare_data.split('\n').filter((line) => regIpV4.test(line));
- ip_ranges = [... ip_ranges, ... items];
- })
- .then(() => {
- return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
- })
- .then((cloudfare_data) => {
- let items = cloudfare_data.split('\n').filter((line) => regIpV6.test(line));
- ip_ranges = [... ip_ranges, ... items];
- })
- .then(() => {
- let clean_ip_ranges = [];
- ip_ranges.map((range) => {
- if (range) {
- clean_ip_ranges.push(range);
- }
- });
-
- return internalIpRanges.generateConfig(clean_ip_ranges)
- .then(() => {
- if (internalIpRanges.iteration_count) {
- // Reload nginx
- return internalNginx.reload();
- }
- });
- })
- .then(() => {
- internalIpRanges.interval_processing = false;
- internalIpRanges.iteration_count++;
- })
- .catch((err) => {
- logger.error(err.message);
- internalIpRanges.interval_processing = false;
- });
- }
- },
-
- /**
- * @param {Array} ip_ranges
- * @returns {Promise}
- */
- generateConfig: (ip_ranges) => {
- const renderEngine = utils.getRenderEngine();
- return new Promise((resolve, reject) => {
- let template = null;
- let filename = '/etc/nginx/conf.d/include/ip_ranges.conf';
- try {
- template = fs.readFileSync(__dirname + '/../templates/ip_ranges.conf', {encoding: 'utf8'});
- } catch (err) {
- reject(new error.ConfigurationError(err.message));
- return;
- }
-
- renderEngine
- .parseAndRender(template, {ip_ranges: ip_ranges})
- .then((config_text) => {
- fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
- resolve(true);
- })
- .catch((err) => {
- logger.warn('Could not write ' + filename + ':', err.message);
- reject(new error.ConfigurationError(err.message));
- });
- });
- }
-};
-
-module.exports = internalIpRanges;
diff --git a/backend/internal/nginx.js b/backend/internal/nginx.js
deleted file mode 100644
index 59694d3c..00000000
--- a/backend/internal/nginx.js
+++ /dev/null
@@ -1,436 +0,0 @@
-const _ = require('lodash');
-const fs = require('node:fs');
-const logger = require('../logger').nginx;
-const config = require('../lib/config');
-const utils = require('../lib/utils');
-const error = require('../lib/error');
-
-const internalNginx = {
-
- /**
- * This will:
- * - test the nginx config first to make sure it's OK
- * - create / recreate the config for the host
- * - test again
- * - IF OK: update the meta with online status
- * - IF BAD: update the meta with offline status and remove the config entirely
- * - then reload nginx
- *
- * @param {Object|String} model
- * @param {String} host_type
- * @param {Object} host
- * @returns {Promise}
- */
- configure: (model, host_type, host) => {
- let combined_meta = {};
-
- return internalNginx.test()
- .then(() => {
- // Nginx is OK
- // We're deleting this config regardless.
- // Don't throw errors, as the file may not exist at all
- // Delete the .err file too
- return internalNginx.deleteConfig(host_type, host, false, true);
- })
- .then(() => {
- return internalNginx.generateConfig(host_type, host);
- })
- .then(() => {
- // Test nginx again and update meta with result
- return internalNginx.test()
- .then(() => {
- // nginx is ok
- combined_meta = _.assign({}, host.meta, {
- nginx_online: true,
- nginx_err: null
- });
-
- return model
- .query()
- .where('id', host.id)
- .patch({
- meta: combined_meta
- });
- })
- .catch((err) => {
- // Remove the error_log line because it's a docker-ism false positive that doesn't need to be reported.
- // It will always look like this:
- // nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (6: No such device or address)
-
- const valid_lines = [];
- const err_lines = err.message.split('\n');
- err_lines.map((line) => {
- if (line.indexOf('/var/log/nginx/error.log') === -1) {
- valid_lines.push(line);
- }
- });
-
- if (config.debug()) {
- logger.error('Nginx test failed:', valid_lines.join('\n'));
- }
-
- // config is bad, update meta and delete config
- combined_meta = _.assign({}, host.meta, {
- nginx_online: false,
- nginx_err: valid_lines.join('\n')
- });
-
- return model
- .query()
- .where('id', host.id)
- .patch({
- meta: combined_meta
- })
- .then(() => {
- internalNginx.renameConfigAsError(host_type, host);
- })
- .then(() => {
- return internalNginx.deleteConfig(host_type, host, true);
- });
- });
- })
- .then(() => {
- return internalNginx.reload();
- })
- .then(() => {
- return combined_meta;
- });
- },
-
- /**
- * @returns {Promise}
- */
- test: () => {
- if (config.debug()) {
- logger.info('Testing Nginx configuration');
- }
-
- return utils.execFile('/usr/sbin/nginx', ['-t', '-g', 'error_log off;']);
- },
-
- /**
- * @returns {Promise}
- */
- reload: () => {
- return internalNginx.test()
- .then(() => {
- logger.info('Reloading Nginx');
- return utils.execFile('/usr/sbin/nginx', ['-s', 'reload']);
- });
- },
-
- /**
- * @param {String} host_type
- * @param {Integer} host_id
- * @returns {String}
- */
- getConfigName: (host_type, host_id) => {
- if (host_type === 'default') {
- return '/data/nginx/default_host/site.conf';
- }
- return `/data/nginx/${internalNginx.getFileFriendlyHostType(host_type)}/${host_id}.conf`;
- },
-
- /**
- * Generates custom locations
- * @param {Object} host
- * @returns {Promise}
- */
- renderLocations: (host) => {
- return new Promise((resolve, reject) => {
- let template;
-
- try {
- template = fs.readFileSync(`${__dirname}/../templates/_location.conf`, {encoding: 'utf8'});
- } catch (err) {
- reject(new error.ConfigurationError(err.message));
- return;
- }
-
- const renderEngine = utils.getRenderEngine();
- let renderedLocations = '';
-
- const locationRendering = async () => {
- for (let i = 0; i < host.locations.length; i++) {
- const locationCopy = Object.assign({}, {access_list_id: host.access_list_id}, {certificate_id: host.certificate_id},
- {ssl_forced: host.ssl_forced}, {caching_enabled: host.caching_enabled}, {block_exploits: host.block_exploits},
- {allow_websocket_upgrade: host.allow_websocket_upgrade}, {http2_support: host.http2_support},
- {hsts_enabled: host.hsts_enabled}, {hsts_subdomains: host.hsts_subdomains}, {access_list: host.access_list},
- {certificate: host.certificate}, host.locations[i]);
-
- if (locationCopy.forward_host.indexOf('/') > -1) {
- const splitted = locationCopy.forward_host.split('/');
-
- locationCopy.forward_host = splitted.shift();
- locationCopy.forward_path = `/${splitted.join('/')}`;
- }
-
- // eslint-disable-next-line
- renderedLocations += await renderEngine.parseAndRender(template, locationCopy);
- }
-
- };
-
- locationRendering().then(() => resolve(renderedLocations));
-
- });
- },
-
- /**
- * @param {String} host_type
- * @param {Object} host
- * @returns {Promise}
- */
- generateConfig: (host_type, host_row) => {
- // Prevent modifying the original object:
- const host = JSON.parse(JSON.stringify(host_row));
- const nice_host_type = internalNginx.getFileFriendlyHostType(host_type);
-
- if (config.debug()) {
- logger.info(`Generating ${nice_host_type} Config:`, JSON.stringify(host, null, 2));
- }
-
- const renderEngine = utils.getRenderEngine();
-
- return new Promise((resolve, reject) => {
- let template = null;
- const filename = internalNginx.getConfigName(nice_host_type, host.id);
-
- try {
- template = fs.readFileSync(`${__dirname}/../templates/${nice_host_type}.conf`, {encoding: 'utf8'});
- } catch (err) {
- reject(new error.ConfigurationError(err.message));
- return;
- }
-
- let locationsPromise;
- let origLocations;
-
- // Manipulate the data a bit before sending it to the template
- if (nice_host_type !== 'default') {
- host.use_default_location = true;
- if (typeof host.advanced_config !== 'undefined' && host.advanced_config) {
- host.use_default_location = !internalNginx.advancedConfigHasDefaultLocation(host.advanced_config);
- }
- }
-
- if (host.locations) {
- //logger.info ('host.locations = ' + JSON.stringify(host.locations, null, 2));
- origLocations = [].concat(host.locations);
- locationsPromise = internalNginx.renderLocations(host).then((renderedLocations) => {
- host.locations = renderedLocations;
- });
-
- // Allow someone who is using / custom location path to use it, and skip the default / location
- _.map(host.locations, (location) => {
- if (location.path === '/') {
- host.use_default_location = false;
- }
- });
-
- } else {
- locationsPromise = Promise.resolve();
- }
-
- // Set the IPv6 setting for the host
- host.ipv6 = internalNginx.ipv6Enabled();
-
- locationsPromise.then(() => {
- renderEngine
- .parseAndRender(template, host)
- .then((config_text) => {
- fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
-
- if (config.debug()) {
- logger.success('Wrote config:', filename, config_text);
- }
-
- // Restore locations array
- host.locations = origLocations;
-
- resolve(true);
- })
- .catch((err) => {
- if (config.debug()) {
- logger.warn(`Could not write ${filename}:`, err.message);
- }
-
- reject(new error.ConfigurationError(err.message));
- });
- });
- });
- },
-
- /**
- * This generates a temporary nginx config listening on port 80 for the domain names listed
- * in the certificate setup. It allows the letsencrypt acme challenge to be requested by letsencrypt
- * when requesting a certificate without having a hostname set up already.
- *
- * @param {Object} certificate
- * @returns {Promise}
- */
- generateLetsEncryptRequestConfig: (certificate) => {
- if (config.debug()) {
- logger.info('Generating LetsEncrypt Request Config:', certificate);
- }
-
- const renderEngine = utils.getRenderEngine();
-
- return new Promise((resolve, reject) => {
- let template = null;
- const filename = `/data/nginx/temp/letsencrypt_${certificate.id}.conf`;
-
- try {
- template = fs.readFileSync(`${__dirname}/../templates/letsencrypt-request.conf`, {encoding: 'utf8'});
- } catch (err) {
- reject(new error.ConfigurationError(err.message));
- return;
- }
-
- certificate.ipv6 = internalNginx.ipv6Enabled();
-
- renderEngine
- .parseAndRender(template, certificate)
- .then((config_text) => {
- fs.writeFileSync(filename, config_text, {encoding: 'utf8'});
-
- if (config.debug()) {
- logger.success('Wrote config:', filename, config_text);
- }
-
- resolve(true);
- })
- .catch((err) => {
- if (config.debug()) {
- logger.warn(`Could not write ${filename}:`, err.message);
- }
-
- reject(new error.ConfigurationError(err.message));
- });
- });
- },
-
- /**
- * A simple wrapper around unlinkSync that writes to the logger
- *
- * @param {String} filename
- */
- deleteFile: (filename) => {
- logger.debug(`Deleting file: ${filename}`);
- try {
- fs.unlinkSync(filename);
- } catch (err) {
- logger.debug('Could not delete file:', JSON.stringify(err, null, 2));
- }
- },
-
- /**
- *
- * @param {String} host_type
- * @returns String
- */
- getFileFriendlyHostType: (host_type) => {
- return host_type.replace(/-/g, '_');
- },
-
- /**
- * This removes the temporary nginx config file generated by `generateLetsEncryptRequestConfig`
- *
- * @param {Object} certificate
- * @returns {Promise}
- */
- deleteLetsEncryptRequestConfig: (certificate) => {
- const config_file = `/data/nginx/temp/letsencrypt_${certificate.id}.conf`;
- return new Promise((resolve/*, reject*/) => {
- internalNginx.deleteFile(config_file);
- resolve();
- });
- },
-
- /**
- * @param {String} host_type
- * @param {Object} [host]
- * @param {Boolean} [delete_err_file]
- * @returns {Promise}
- */
- deleteConfig: (host_type, host, delete_err_file) => {
- const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
- const config_file_err = `${config_file}.err`;
-
- return new Promise((resolve/*, reject*/) => {
- internalNginx.deleteFile(config_file);
- if (delete_err_file) {
- internalNginx.deleteFile(config_file_err);
- }
- resolve();
- });
- },
-
- /**
- * @param {String} host_type
- * @param {Object} [host]
- * @returns {Promise}
- */
- renameConfigAsError: (host_type, host) => {
- const config_file = internalNginx.getConfigName(internalNginx.getFileFriendlyHostType(host_type), typeof host === 'undefined' ? 0 : host.id);
- const config_file_err = `${config_file}.err`;
-
- return new Promise((resolve/*, reject*/) => {
- fs.unlink(config_file, () => {
- // ignore result, continue
- fs.rename(config_file, config_file_err, () => {
- // also ignore result, as this is a debugging informative file anyway
- resolve();
- });
- });
- });
- },
-
- /**
- * @param {String} host_type
- * @param {Array} hosts
- * @returns {Promise}
- */
- bulkGenerateConfigs: (host_type, hosts) => {
- const promises = [];
- hosts.map((host) => {
- promises.push(internalNginx.generateConfig(host_type, host));
- });
-
- return Promise.all(promises);
- },
-
- /**
- * @param {String} host_type
- * @param {Array} hosts
- * @returns {Promise}
- */
- bulkDeleteConfigs: (host_type, hosts) => {
- const promises = [];
- hosts.map((host) => {
- promises.push(internalNginx.deleteConfig(host_type, host, true));
- });
-
- return Promise.all(promises);
- },
-
- /**
- * @param {string} config
- * @returns {boolean}
- */
- advancedConfigHasDefaultLocation: (cfg) => !!cfg.match(/^(?:.*;)?\s*?location\s*?\/\s*?{/im),
-
- /**
- * @returns {boolean}
- */
- ipv6Enabled: () => {
- if (typeof process.env.DISABLE_IPV6 !== 'undefined') {
- const disabled = process.env.DISABLE_IPV6.toLowerCase();
- return !(disabled === 'on' || disabled === 'true' || disabled === '1' || disabled === 'yes');
- }
-
- return true;
- }
-};
-
-module.exports = internalNginx;
diff --git a/backend/internal/proxy-host.js b/backend/internal/proxy-host.js
deleted file mode 100644
index 32f2bc0d..00000000
--- a/backend/internal/proxy-host.js
+++ /dev/null
@@ -1,472 +0,0 @@
-const _ = require('lodash');
-const error = require('../lib/error');
-const utils = require('../lib/utils');
-const proxyHostModel = require('../models/proxy_host');
-const internalHost = require('./host');
-const internalNginx = require('./nginx');
-const internalAuditLog = require('./audit-log');
-const internalCertificate = require('./certificate');
-const {castJsonIfNeed} = require('../lib/helpers');
-
-function omissions () {
- return ['is_deleted', 'owner.is_deleted'];
-}
-
-const internalProxyHost = {
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @returns {Promise}
- */
- create: (access, data) => {
- let create_certificate = data.certificate_id === 'new';
-
- if (create_certificate) {
- delete data.certificate_id;
- }
-
- return access.can('proxy_hosts:create', data)
- .then(() => {
- // Get a list of the domain names and check each of them against existing records
- let domain_name_check_promises = [];
-
- data.domain_names.map(function (domain_name) {
- domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name));
- });
-
- return Promise.all(domain_name_check_promises)
- .then((check_results) => {
- check_results.map(function (result) {
- if (result.is_taken) {
- throw new error.ValidationError(result.hostname + ' is already in use');
- }
- });
- });
- })
- .then(() => {
- // At this point the domains should have been checked
- data.owner_user_id = access.token.getUserId(1);
- data = internalHost.cleanSslHstsData(data);
-
- // Fix for db field not having a default value
- // for this optional field.
- if (typeof data.advanced_config === 'undefined') {
- data.advanced_config = '';
- }
-
- return proxyHostModel
- .query()
- .insertAndFetch(data)
- .then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (create_certificate) {
- return internalCertificate.createQuickCertificate(access, data)
- .then((cert) => {
- // update host with cert id
- return internalProxyHost.update(access, {
- id: row.id,
- certificate_id: cert.id
- });
- })
- .then(() => {
- return row;
- });
- } else {
- return row;
- }
- })
- .then((row) => {
- // re-fetch with cert
- return internalProxyHost.get(access, {
- id: row.id,
- expand: ['certificate', 'owner', 'access_list.[clients,items]']
- });
- })
- .then((row) => {
- // Configure nginx
- return internalNginx.configure(proxyHostModel, 'proxy_host', row)
- .then(() => {
- return row;
- });
- })
- .then((row) => {
- // Audit log
- data.meta = _.assign({}, data.meta || {}, row.meta);
-
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'created',
- object_type: 'proxy-host',
- object_id: row.id,
- meta: data
- })
- .then(() => {
- return row;
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @return {Promise}
- */
- update: (access, data) => {
- let create_certificate = data.certificate_id === 'new';
-
- if (create_certificate) {
- delete data.certificate_id;
- }
-
- return access.can('proxy_hosts:update', data.id)
- .then((/*access_data*/) => {
- // Get a list of the domain names and check each of them against existing records
- let domain_name_check_promises = [];
-
- if (typeof data.domain_names !== 'undefined') {
- data.domain_names.map(function (domain_name) {
- domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name, 'proxy', data.id));
- });
-
- return Promise.all(domain_name_check_promises)
- .then((check_results) => {
- check_results.map(function (result) {
- if (result.is_taken) {
- throw new error.ValidationError(result.hostname + ' is already in use');
- }
- });
- });
- }
- })
- .then(() => {
- return internalProxyHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (row.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError('Proxy Host could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
- }
-
- if (create_certificate) {
- return internalCertificate.createQuickCertificate(access, {
- domain_names: data.domain_names || row.domain_names,
- meta: _.assign({}, row.meta, data.meta)
- })
- .then((cert) => {
- // update host with cert id
- data.certificate_id = cert.id;
- })
- .then(() => {
- return row;
- });
- } else {
- return row;
- }
- })
- .then((row) => {
- // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
- data = _.assign({}, {
- domain_names: row.domain_names
- }, data);
-
- data = internalHost.cleanSslHstsData(data, row);
-
- return proxyHostModel
- .query()
- .where({id: data.id})
- .patch(data)
- .then(utils.omitRow(omissions()))
- .then((saved_row) => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'proxy-host',
- object_id: row.id,
- meta: data
- })
- .then(() => {
- return saved_row;
- });
- });
- })
- .then(() => {
- return internalProxyHost.get(access, {
- id: data.id,
- expand: ['owner', 'certificate', 'access_list.[clients,items]']
- })
- .then((row) => {
- if (!row.enabled) {
- // No need to add nginx config if host is disabled
- return row;
- }
- // Configure nginx
- return internalNginx.configure(proxyHostModel, 'proxy_host', row)
- .then((new_meta) => {
- row.meta = new_meta;
- row = internalHost.cleanRowCertificateMeta(row);
- return _.omit(row, omissions());
- });
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {Array} [data.expand]
- * @param {Array} [data.omit]
- * @return {Promise}
- */
- get: (access, data) => {
- if (typeof data === 'undefined') {
- data = {};
- }
-
- return access.can('proxy_hosts:get', data.id)
- .then((access_data) => {
- let query = proxyHostModel
- .query()
- .where('is_deleted', 0)
- .andWhere('id', data.id)
- .allowGraph('[owner,access_list.[clients,items],certificate]')
- .first();
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- if (typeof data.expand !== 'undefined' && data.expand !== null) {
- query.withGraphFetched('[' + data.expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
- row = internalHost.cleanRowCertificateMeta(row);
- // Custom omissions
- if (typeof data.omit !== 'undefined' && data.omit !== null) {
- row = _.omit(row, data.omit);
- }
- return row;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- delete: (access, data) => {
- return access.can('proxy_hosts:delete', data.id)
- .then(() => {
- return internalProxyHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
-
- return proxyHostModel
- .query()
- .where('id', row.id)
- .patch({
- is_deleted: 1
- })
- .then(() => {
- // Delete Nginx Config
- return internalNginx.deleteConfig('proxy_host', row)
- .then(() => {
- return internalNginx.reload();
- });
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'deleted',
- object_type: 'proxy-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- enable: (access, data) => {
- return access.can('proxy_hosts:update', data.id)
- .then(() => {
- return internalProxyHost.get(access, {
- id: data.id,
- expand: ['certificate', 'owner', 'access_list']
- });
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- } else if (row.enabled) {
- throw new error.ValidationError('Host is already enabled');
- }
-
- row.enabled = 1;
-
- return proxyHostModel
- .query()
- .where('id', row.id)
- .patch({
- enabled: 1
- })
- .then(() => {
- // Configure nginx
- return internalNginx.configure(proxyHostModel, 'proxy_host', row);
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'enabled',
- object_type: 'proxy-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- disable: (access, data) => {
- return access.can('proxy_hosts:update', data.id)
- .then(() => {
- return internalProxyHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- } else if (!row.enabled) {
- throw new error.ValidationError('Host is already disabled');
- }
-
- row.enabled = 0;
-
- return proxyHostModel
- .query()
- .where('id', row.id)
- .patch({
- enabled: 0
- })
- .then(() => {
- // Delete Nginx Config
- return internalNginx.deleteConfig('proxy_host', row)
- .then(() => {
- return internalNginx.reload();
- });
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'disabled',
- object_type: 'proxy-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * All Hosts
- *
- * @param {Access} access
- * @param {Array} [expand]
- * @param {String} [search_query]
- * @returns {Promise}
- */
- getAll: (access, expand, search_query) => {
- return access.can('proxy_hosts:list')
- .then((access_data) => {
- let query = proxyHostModel
- .query()
- .where('is_deleted', 0)
- .groupBy('id')
- .allowGraph('[owner,access_list,certificate]')
- .orderBy(castJsonIfNeed('domain_names'), 'ASC');
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- // Query is used for searching
- if (typeof search_query === 'string' && search_query.length > 0) {
- query.where(function () {
- this.where(castJsonIfNeed('domain_names'), 'like', `%${search_query}%`);
- });
- }
-
- if (typeof expand !== 'undefined' && expand !== null) {
- query.withGraphFetched('[' + expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRows(omissions()));
- })
- .then((rows) => {
- if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
- return internalHost.cleanAllRowsCertificateMeta(rows);
- }
-
- return rows;
- });
- },
-
- /**
- * Report use
- *
- * @param {Number} user_id
- * @param {String} visibility
- * @returns {Promise}
- */
- getCount: (user_id, visibility) => {
- let query = proxyHostModel
- .query()
- .count('id as count')
- .where('is_deleted', 0);
-
- if (visibility !== 'all') {
- query.andWhere('owner_user_id', user_id);
- }
-
- return query.first()
- .then((row) => {
- return parseInt(row.count, 10);
- });
- }
-};
-
-module.exports = internalProxyHost;
diff --git a/backend/internal/redirection-host.js b/backend/internal/redirection-host.js
deleted file mode 100644
index 6a81b866..00000000
--- a/backend/internal/redirection-host.js
+++ /dev/null
@@ -1,465 +0,0 @@
-const _ = require('lodash');
-const error = require('../lib/error');
-const utils = require('../lib/utils');
-const redirectionHostModel = require('../models/redirection_host');
-const internalHost = require('./host');
-const internalNginx = require('./nginx');
-const internalAuditLog = require('./audit-log');
-const internalCertificate = require('./certificate');
-const {castJsonIfNeed} = require('../lib/helpers');
-
-function omissions () {
- return ['is_deleted'];
-}
-
-const internalRedirectionHost = {
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @returns {Promise}
- */
- create: (access, data) => {
- let create_certificate = data.certificate_id === 'new';
-
- if (create_certificate) {
- delete data.certificate_id;
- }
-
- return access.can('redirection_hosts:create', data)
- .then((/*access_data*/) => {
- // Get a list of the domain names and check each of them against existing records
- let domain_name_check_promises = [];
-
- data.domain_names.map(function (domain_name) {
- domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name));
- });
-
- return Promise.all(domain_name_check_promises)
- .then((check_results) => {
- check_results.map(function (result) {
- if (result.is_taken) {
- throw new error.ValidationError(result.hostname + ' is already in use');
- }
- });
- });
- })
- .then(() => {
- // At this point the domains should have been checked
- data.owner_user_id = access.token.getUserId(1);
- data = internalHost.cleanSslHstsData(data);
-
- // Fix for db field not having a default value
- // for this optional field.
- if (typeof data.advanced_config === 'undefined') {
- data.advanced_config = '';
- }
-
- return redirectionHostModel
- .query()
- .insertAndFetch(data)
- .then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (create_certificate) {
- return internalCertificate.createQuickCertificate(access, data)
- .then((cert) => {
- // update host with cert id
- return internalRedirectionHost.update(access, {
- id: row.id,
- certificate_id: cert.id
- });
- })
- .then(() => {
- return row;
- });
- }
- return row;
- })
- .then((row) => {
- // re-fetch with cert
- return internalRedirectionHost.get(access, {
- id: row.id,
- expand: ['certificate', 'owner']
- });
- })
- .then((row) => {
- // Configure nginx
- return internalNginx.configure(redirectionHostModel, 'redirection_host', row)
- .then(() => {
- return row;
- });
- })
- .then((row) => {
- data.meta = _.assign({}, data.meta || {}, row.meta);
-
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'created',
- object_type: 'redirection-host',
- object_id: row.id,
- meta: data
- })
- .then(() => {
- return row;
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @return {Promise}
- */
- update: (access, data) => {
- let create_certificate = data.certificate_id === 'new';
-
- if (create_certificate) {
- delete data.certificate_id;
- }
-
- return access.can('redirection_hosts:update', data.id)
- .then((/*access_data*/) => {
- // Get a list of the domain names and check each of them against existing records
- let domain_name_check_promises = [];
-
- if (typeof data.domain_names !== 'undefined') {
- data.domain_names.map(function (domain_name) {
- domain_name_check_promises.push(internalHost.isHostnameTaken(domain_name, 'redirection', data.id));
- });
-
- return Promise.all(domain_name_check_promises)
- .then((check_results) => {
- check_results.map(function (result) {
- if (result.is_taken) {
- throw new error.ValidationError(result.hostname + ' is already in use');
- }
- });
- });
- }
- })
- .then(() => {
- return internalRedirectionHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (row.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError('Redirection Host could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
- }
-
- if (create_certificate) {
- return internalCertificate.createQuickCertificate(access, {
- domain_names: data.domain_names || row.domain_names,
- meta: _.assign({}, row.meta, data.meta)
- })
- .then((cert) => {
- // update host with cert id
- data.certificate_id = cert.id;
- })
- .then(() => {
- return row;
- });
- } else {
- return row;
- }
- })
- .then((row) => {
- // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
- data = _.assign({}, {
- domain_names: row.domain_names
- }, data);
-
- data = internalHost.cleanSslHstsData(data, row);
-
- return redirectionHostModel
- .query()
- .where({id: data.id})
- .patch(data)
- .then((saved_row) => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'redirection-host',
- object_id: row.id,
- meta: data
- })
- .then(() => {
- return _.omit(saved_row, omissions());
- });
- });
- })
- .then(() => {
- return internalRedirectionHost.get(access, {
- id: data.id,
- expand: ['owner', 'certificate']
- })
- .then((row) => {
- // Configure nginx
- return internalNginx.configure(redirectionHostModel, 'redirection_host', row)
- .then((new_meta) => {
- row.meta = new_meta;
- row = internalHost.cleanRowCertificateMeta(row);
- return _.omit(row, omissions());
- });
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {Array} [data.expand]
- * @param {Array} [data.omit]
- * @return {Promise}
- */
- get: (access, data) => {
- if (typeof data === 'undefined') {
- data = {};
- }
-
- return access.can('redirection_hosts:get', data.id)
- .then((access_data) => {
- let query = redirectionHostModel
- .query()
- .where('is_deleted', 0)
- .andWhere('id', data.id)
- .allowGraph('[owner,certificate]')
- .first();
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- if (typeof data.expand !== 'undefined' && data.expand !== null) {
- query.withGraphFetched('[' + data.expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
- row = internalHost.cleanRowCertificateMeta(row);
- // Custom omissions
- if (typeof data.omit !== 'undefined' && data.omit !== null) {
- row = _.omit(row, data.omit);
- }
- return row;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- delete: (access, data) => {
- return access.can('redirection_hosts:delete', data.id)
- .then(() => {
- return internalRedirectionHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
-
- return redirectionHostModel
- .query()
- .where('id', row.id)
- .patch({
- is_deleted: 1
- })
- .then(() => {
- // Delete Nginx Config
- return internalNginx.deleteConfig('redirection_host', row)
- .then(() => {
- return internalNginx.reload();
- });
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'deleted',
- object_type: 'redirection-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- enable: (access, data) => {
- return access.can('redirection_hosts:update', data.id)
- .then(() => {
- return internalRedirectionHost.get(access, {
- id: data.id,
- expand: ['certificate', 'owner']
- });
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- } else if (row.enabled) {
- throw new error.ValidationError('Host is already enabled');
- }
-
- row.enabled = 1;
-
- return redirectionHostModel
- .query()
- .where('id', row.id)
- .patch({
- enabled: 1
- })
- .then(() => {
- // Configure nginx
- return internalNginx.configure(redirectionHostModel, 'redirection_host', row);
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'enabled',
- object_type: 'redirection-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- disable: (access, data) => {
- return access.can('redirection_hosts:update', data.id)
- .then(() => {
- return internalRedirectionHost.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- } else if (!row.enabled) {
- throw new error.ValidationError('Host is already disabled');
- }
-
- row.enabled = 0;
-
- return redirectionHostModel
- .query()
- .where('id', row.id)
- .patch({
- enabled: 0
- })
- .then(() => {
- // Delete Nginx Config
- return internalNginx.deleteConfig('redirection_host', row)
- .then(() => {
- return internalNginx.reload();
- });
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'disabled',
- object_type: 'redirection-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * All Hosts
- *
- * @param {Access} access
- * @param {Array} [expand]
- * @param {String} [search_query]
- * @returns {Promise}
- */
- getAll: (access, expand, search_query) => {
- return access.can('redirection_hosts:list')
- .then((access_data) => {
- let query = redirectionHostModel
- .query()
- .where('is_deleted', 0)
- .groupBy('id')
- .allowGraph('[owner,certificate]')
- .orderBy(castJsonIfNeed('domain_names'), 'ASC');
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- // Query is used for searching
- if (typeof search_query === 'string' && search_query.length > 0) {
- query.where(function () {
- this.where(castJsonIfNeed('domain_names'), 'like', `%${search_query}%`);
- });
- }
-
- if (typeof expand !== 'undefined' && expand !== null) {
- query.withGraphFetched('[' + expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRows(omissions()));
- })
- .then((rows) => {
- if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
- return internalHost.cleanAllRowsCertificateMeta(rows);
- }
-
- return rows;
- });
- },
-
- /**
- * Report use
- *
- * @param {Number} user_id
- * @param {String} visibility
- * @returns {Promise}
- */
- getCount: (user_id, visibility) => {
- let query = redirectionHostModel
- .query()
- .count('id as count')
- .where('is_deleted', 0);
-
- if (visibility !== 'all') {
- query.andWhere('owner_user_id', user_id);
- }
-
- return query.first()
- .then((row) => {
- return parseInt(row.count, 10);
- });
- }
-};
-
-module.exports = internalRedirectionHost;
diff --git a/backend/internal/report.js b/backend/internal/report.js
deleted file mode 100644
index 4dde659b..00000000
--- a/backend/internal/report.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const internalProxyHost = require('./proxy-host');
-const internalRedirectionHost = require('./redirection-host');
-const internalDeadHost = require('./dead-host');
-const internalStream = require('./stream');
-
-const internalReport = {
-
- /**
- * @param {Access} access
- * @return {Promise}
- */
- getHostsReport: (access) => {
- return access.can('reports:hosts', 1)
- .then((access_data) => {
- let user_id = access.token.getUserId(1);
-
- let promises = [
- internalProxyHost.getCount(user_id, access_data.visibility),
- internalRedirectionHost.getCount(user_id, access_data.visibility),
- internalStream.getCount(user_id, access_data.visibility),
- internalDeadHost.getCount(user_id, access_data.visibility)
- ];
-
- return Promise.all(promises);
- })
- .then((counts) => {
- return {
- proxy: counts.shift(),
- redirection: counts.shift(),
- stream: counts.shift(),
- dead: counts.shift()
- };
- });
-
- }
-};
-
-module.exports = internalReport;
diff --git a/backend/internal/setting.js b/backend/internal/setting.js
deleted file mode 100644
index d4ac67d8..00000000
--- a/backend/internal/setting.js
+++ /dev/null
@@ -1,133 +0,0 @@
-const fs = require('fs');
-const error = require('../lib/error');
-const settingModel = require('../models/setting');
-const internalNginx = require('./nginx');
-
-const internalSetting = {
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {String} data.id
- * @return {Promise}
- */
- update: (access, data) => {
- return access.can('settings:update', data.id)
- .then((/*access_data*/) => {
- return internalSetting.get(access, {id: data.id});
- })
- .then((row) => {
- if (row.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError('Setting could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
- }
-
- return settingModel
- .query()
- .where({id: data.id})
- .patch(data);
- })
- .then(() => {
- return internalSetting.get(access, {
- id: data.id
- });
- })
- .then((row) => {
- if (row.id === 'default-site') {
- // write the html if we need to
- if (row.value === 'html') {
- fs.writeFileSync('/data/nginx/default_www/index.html', row.meta.html, {encoding: 'utf8'});
- }
-
- // Configure nginx
- return internalNginx.deleteConfig('default')
- .then(() => {
- return internalNginx.generateConfig('default', row);
- })
- .then(() => {
- return internalNginx.test();
- })
- .then(() => {
- return internalNginx.reload();
- })
- .then(() => {
- return row;
- })
- .catch((/*err*/) => {
- internalNginx.deleteConfig('default')
- .then(() => {
- return internalNginx.test();
- })
- .then(() => {
- return internalNginx.reload();
- })
- .then(() => {
- // I'm being slack here I know..
- throw new error.ValidationError('Could not reconfigure Nginx. Please check logs.');
- });
- });
- } else {
- return row;
- }
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {String} data.id
- * @return {Promise}
- */
- get: (access, data) => {
- return access.can('settings:get', data.id)
- .then(() => {
- return settingModel
- .query()
- .where('id', data.id)
- .first();
- })
- .then((row) => {
- if (row) {
- return row;
- } else {
- throw new error.ItemNotFoundError(data.id);
- }
- });
- },
-
- /**
- * This will only count the settings
- *
- * @param {Access} access
- * @returns {*}
- */
- getCount: (access) => {
- return access.can('settings:list')
- .then(() => {
- return settingModel
- .query()
- .count('id as count')
- .first();
- })
- .then((row) => {
- return parseInt(row.count, 10);
- });
- },
-
- /**
- * All settings
- *
- * @param {Access} access
- * @returns {Promise}
- */
- getAll: (access) => {
- return access.can('settings:list')
- .then(() => {
- return settingModel
- .query()
- .orderBy('description', 'ASC');
- });
- }
-};
-
-module.exports = internalSetting;
diff --git a/backend/internal/stream.js b/backend/internal/stream.js
deleted file mode 100644
index 50ce0832..00000000
--- a/backend/internal/stream.js
+++ /dev/null
@@ -1,424 +0,0 @@
-const _ = require('lodash');
-const error = require('../lib/error');
-const utils = require('../lib/utils');
-const streamModel = require('../models/stream');
-const internalNginx = require('./nginx');
-const internalAuditLog = require('./audit-log');
-const internalCertificate = require('./certificate');
-const internalHost = require('./host');
-const {castJsonIfNeed} = require('../lib/helpers');
-
-function omissions () {
- return ['is_deleted', 'owner.is_deleted', 'certificate.is_deleted'];
-}
-
-const internalStream = {
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @returns {Promise}
- */
- create: (access, data) => {
- const create_certificate = data.certificate_id === 'new';
-
- if (create_certificate) {
- delete data.certificate_id;
- }
-
- return access.can('streams:create', data)
- .then((/*access_data*/) => {
- // TODO: At this point the existing ports should have been checked
- data.owner_user_id = access.token.getUserId(1);
-
- if (typeof data.meta === 'undefined') {
- data.meta = {};
- }
-
- // streams aren't routed by domain name so don't store domain names in the DB
- let data_no_domains = structuredClone(data);
- delete data_no_domains.domain_names;
-
- return streamModel
- .query()
- .insertAndFetch(data_no_domains)
- .then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (create_certificate) {
- return internalCertificate.createQuickCertificate(access, data)
- .then((cert) => {
- // update host with cert id
- return internalStream.update(access, {
- id: row.id,
- certificate_id: cert.id
- });
- })
- .then(() => {
- return row;
- });
- } else {
- return row;
- }
- })
- .then((row) => {
- // re-fetch with cert
- return internalStream.get(access, {
- id: row.id,
- expand: ['certificate', 'owner']
- });
- })
- .then((row) => {
- // Configure nginx
- return internalNginx.configure(streamModel, 'stream', row)
- .then(() => {
- return row;
- });
- })
- .then((row) => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'created',
- object_type: 'stream',
- object_id: row.id,
- meta: data
- })
- .then(() => {
- return row;
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @return {Promise}
- */
- update: (access, data) => {
- const create_certificate = data.certificate_id === 'new';
-
- if (create_certificate) {
- delete data.certificate_id;
- }
-
- return access.can('streams:update', data.id)
- .then((/*access_data*/) => {
- // TODO: at this point the existing streams should have been checked
- return internalStream.get(access, {id: data.id});
- })
- .then((row) => {
- if (row.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError('Stream could not be updated, IDs do not match: ' + row.id + ' !== ' + data.id);
- }
-
- if (create_certificate) {
- return internalCertificate.createQuickCertificate(access, {
- domain_names: data.domain_names || row.domain_names,
- meta: _.assign({}, row.meta, data.meta)
- })
- .then((cert) => {
- // update host with cert id
- data.certificate_id = cert.id;
- })
- .then(() => {
- return row;
- });
- } else {
- return row;
- }
- })
- .then((row) => {
- // Add domain_names to the data in case it isn't there, so that the audit log renders correctly. The order is important here.
- data = _.assign({}, {
- domain_names: row.domain_names
- }, data);
-
- return streamModel
- .query()
- .patchAndFetchById(row.id, data)
- .then(utils.omitRow(omissions()))
- .then((saved_row) => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'stream',
- object_id: row.id,
- meta: data
- })
- .then(() => {
- return saved_row;
- });
- });
- })
- .then(() => {
- return internalStream.get(access, {id: data.id, expand: ['owner', 'certificate']})
- .then((row) => {
- return internalNginx.configure(streamModel, 'stream', row)
- .then((new_meta) => {
- row.meta = new_meta;
- row = internalHost.cleanRowCertificateMeta(row);
- return _.omit(row, omissions());
- });
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {Array} [data.expand]
- * @param {Array} [data.omit]
- * @return {Promise}
- */
- get: (access, data) => {
- if (typeof data === 'undefined') {
- data = {};
- }
-
- return access.can('streams:get', data.id)
- .then((access_data) => {
- let query = streamModel
- .query()
- .where('is_deleted', 0)
- .andWhere('id', data.id)
- .allowGraph('[owner,certificate]')
- .first();
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- if (typeof data.expand !== 'undefined' && data.expand !== null) {
- query.withGraphFetched('[' + data.expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
- row = internalHost.cleanRowCertificateMeta(row);
- // Custom omissions
- if (typeof data.omit !== 'undefined' && data.omit !== null) {
- row = _.omit(row, data.omit);
- }
- return row;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- delete: (access, data) => {
- return access.can('streams:delete', data.id)
- .then(() => {
- return internalStream.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
-
- return streamModel
- .query()
- .where('id', row.id)
- .patch({
- is_deleted: 1
- })
- .then(() => {
- // Delete Nginx Config
- return internalNginx.deleteConfig('stream', row)
- .then(() => {
- return internalNginx.reload();
- });
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'deleted',
- object_type: 'stream',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- enable: (access, data) => {
- return access.can('streams:update', data.id)
- .then(() => {
- return internalStream.get(access, {
- id: data.id,
- expand: ['certificate', 'owner']
- });
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- } else if (row.enabled) {
- throw new error.ValidationError('Stream is already enabled');
- }
-
- row.enabled = 1;
-
- return streamModel
- .query()
- .where('id', row.id)
- .patch({
- enabled: 1
- })
- .then(() => {
- // Configure nginx
- return internalNginx.configure(streamModel, 'stream', row);
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'enabled',
- object_type: 'stream',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Number} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- disable: (access, data) => {
- return access.can('streams:update', data.id)
- .then(() => {
- return internalStream.get(access, {id: data.id});
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- } else if (!row.enabled) {
- throw new error.ValidationError('Stream is already disabled');
- }
-
- row.enabled = 0;
-
- return streamModel
- .query()
- .where('id', row.id)
- .patch({
- enabled: 0
- })
- .then(() => {
- // Delete Nginx Config
- return internalNginx.deleteConfig('stream', row)
- .then(() => {
- return internalNginx.reload();
- });
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'disabled',
- object_type: 'stream-host',
- object_id: row.id,
- meta: _.omit(row, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * All Streams
- *
- * @param {Access} access
- * @param {Array} [expand]
- * @param {String} [search_query]
- * @returns {Promise}
- */
- getAll: (access, expand, search_query) => {
- return access.can('streams:list')
- .then((access_data) => {
- const query = streamModel
- .query()
- .where('is_deleted', 0)
- .groupBy('id')
- .allowGraph('[owner,certificate]')
- .orderBy('incoming_port', 'ASC');
-
- if (access_data.permission_visibility !== 'all') {
- query.andWhere('owner_user_id', access.token.getUserId(1));
- }
-
- // Query is used for searching
- if (typeof search_query === 'string' && search_query.length > 0) {
- query.where(function () {
- this.where(castJsonIfNeed('incoming_port'), 'like', `%${search_query}%`);
- });
- }
-
- if (typeof expand !== 'undefined' && expand !== null) {
- query.withGraphFetched('[' + expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRows(omissions()));
- })
- .then((rows) => {
- if (typeof expand !== 'undefined' && expand !== null && expand.indexOf('certificate') !== -1) {
- return internalHost.cleanAllRowsCertificateMeta(rows);
- }
-
- return rows;
- });
- },
-
- /**
- * Report use
- *
- * @param {Number} user_id
- * @param {String} visibility
- * @returns {Promise}
- */
- getCount: (user_id, visibility) => {
- const query = streamModel
- .query()
- .count('id AS count')
- .where('is_deleted', 0);
-
- if (visibility !== 'all') {
- query.andWhere('owner_user_id', user_id);
- }
-
- return query.first()
- .then((row) => {
- return parseInt(row.count, 10);
- });
- }
-};
-
-module.exports = internalStream;
diff --git a/backend/internal/token.js b/backend/internal/token.js
deleted file mode 100644
index 0e6dec5e..00000000
--- a/backend/internal/token.js
+++ /dev/null
@@ -1,164 +0,0 @@
-const _ = require('lodash');
-const error = require('../lib/error');
-const userModel = require('../models/user');
-const authModel = require('../models/auth');
-const helpers = require('../lib/helpers');
-const TokenModel = require('../models/token');
-
-const ERROR_MESSAGE_INVALID_AUTH = 'Invalid email or password';
-
-module.exports = {
-
- /**
- * @param {Object} data
- * @param {String} data.identity
- * @param {String} data.secret
- * @param {String} [data.scope]
- * @param {String} [data.expiry]
- * @param {String} [issuer]
- * @returns {Promise}
- */
- getTokenFromEmail: (data, issuer) => {
- let Token = new TokenModel();
-
- data.scope = data.scope || 'user';
- data.expiry = data.expiry || '1d';
-
- return userModel
- .query()
- .where('email', data.identity.toLowerCase().trim())
- .andWhere('is_deleted', 0)
- .andWhere('is_disabled', 0)
- .first()
- .then((user) => {
- if (user) {
- // Get auth
- return authModel
- .query()
- .where('user_id', '=', user.id)
- .where('type', '=', 'password')
- .first()
- .then((auth) => {
- if (auth) {
- return auth.verifyPassword(data.secret)
- .then((valid) => {
- if (valid) {
-
- if (data.scope !== 'user' && _.indexOf(user.roles, data.scope) === -1) {
- // The scope requested doesn't exist as a role against the user,
- // you shall not pass.
- throw new error.AuthError('Invalid scope: ' + data.scope);
- }
-
- // Create a moment of the expiry expression
- let expiry = helpers.parseDatePeriod(data.expiry);
- if (expiry === null) {
- throw new error.AuthError('Invalid expiry time: ' + data.expiry);
- }
-
- return Token.create({
- iss: issuer || 'api',
- attrs: {
- id: user.id
- },
- scope: [data.scope],
- expiresIn: data.expiry
- })
- .then((signed) => {
- return {
- token: signed.token,
- expires: expiry.toISOString()
- };
- });
- } else {
- throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
- }
- });
- } else {
- throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
- }
- });
- } else {
- throw new error.AuthError(ERROR_MESSAGE_INVALID_AUTH);
- }
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} [data]
- * @param {String} [data.expiry]
- * @param {String} [data.scope] Only considered if existing token scope is admin
- * @returns {Promise}
- */
- getFreshToken: (access, data) => {
- let Token = new TokenModel();
-
- data = data || {};
- data.expiry = data.expiry || '1d';
-
- if (access && access.token.getUserId(0)) {
-
- // Create a moment of the expiry expression
- let expiry = helpers.parseDatePeriod(data.expiry);
- if (expiry === null) {
- throw new error.AuthError('Invalid expiry time: ' + data.expiry);
- }
-
- let token_attrs = {
- id: access.token.getUserId(0)
- };
-
- // Only admins can request otherwise scoped tokens
- let scope = access.token.get('scope');
- if (data.scope && access.token.hasScope('admin')) {
- scope = [data.scope];
-
- if (data.scope === 'job-board' || data.scope === 'worker') {
- token_attrs.id = 0;
- }
- }
-
- return Token.create({
- iss: 'api',
- scope: scope,
- attrs: token_attrs,
- expiresIn: data.expiry
- })
- .then((signed) => {
- return {
- token: signed.token,
- expires: expiry.toISOString()
- };
- });
- } else {
- throw new error.AssertionFailedError('Existing token contained invalid user data');
- }
- },
-
- /**
- * @param {Object} user
- * @returns {Promise}
- */
- getTokenFromUser: (user) => {
- const expire = '1d';
- const Token = new TokenModel();
- const expiry = helpers.parseDatePeriod(expire);
-
- return Token.create({
- iss: 'api',
- attrs: {
- id: user.id
- },
- scope: ['user'],
- expiresIn: expire
- })
- .then((signed) => {
- return {
- token: signed.token,
- expires: expiry.toISOString(),
- user: user
- };
- });
- }
-};
diff --git a/backend/internal/user.js b/backend/internal/user.js
deleted file mode 100644
index 742ab65d..00000000
--- a/backend/internal/user.js
+++ /dev/null
@@ -1,513 +0,0 @@
-const _ = require('lodash');
-const error = require('../lib/error');
-const utils = require('../lib/utils');
-const userModel = require('../models/user');
-const userPermissionModel = require('../models/user_permission');
-const authModel = require('../models/auth');
-const gravatar = require('gravatar');
-const internalToken = require('./token');
-const internalAuditLog = require('./audit-log');
-
-function omissions () {
- return ['is_deleted'];
-}
-
-const internalUser = {
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @returns {Promise}
- */
- create: (access, data) => {
- let auth = data.auth || null;
- delete data.auth;
-
- data.avatar = data.avatar || '';
- data.roles = data.roles || [];
-
- if (typeof data.is_disabled !== 'undefined') {
- data.is_disabled = data.is_disabled ? 1 : 0;
- }
-
- return access.can('users:create', data)
- .then(() => {
- data.avatar = gravatar.url(data.email, {default: 'mm'});
-
- return userModel
- .query()
- .insertAndFetch(data)
- .then(utils.omitRow(omissions()));
- })
- .then((user) => {
- if (auth) {
- return authModel
- .query()
- .insert({
- user_id: user.id,
- type: auth.type,
- secret: auth.secret,
- meta: {}
- })
- .then(() => {
- return user;
- });
- } else {
- return user;
- }
- })
- .then((user) => {
- // Create permissions row as well
- let is_admin = data.roles.indexOf('admin') !== -1;
-
- return userPermissionModel
- .query()
- .insert({
- user_id: user.id,
- visibility: is_admin ? 'all' : 'user',
- proxy_hosts: 'manage',
- redirection_hosts: 'manage',
- dead_hosts: 'manage',
- streams: 'manage',
- access_lists: 'manage',
- certificates: 'manage'
- })
- .then(() => {
- return internalUser.get(access, {id: user.id, expand: ['permissions']});
- });
- })
- .then((user) => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'created',
- object_type: 'user',
- object_id: user.id,
- meta: user
- })
- .then(() => {
- return user;
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Integer} data.id
- * @param {String} [data.email]
- * @param {String} [data.name]
- * @return {Promise}
- */
- update: (access, data) => {
- if (typeof data.is_disabled !== 'undefined') {
- data.is_disabled = data.is_disabled ? 1 : 0;
- }
-
- return access.can('users:update', data.id)
- .then(() => {
-
- // Make sure that the user being updated doesn't change their email to another user that is already using it
- // 1. get user we want to update
- return internalUser.get(access, {id: data.id})
- .then((user) => {
-
- // 2. if email is to be changed, find other users with that email
- if (typeof data.email !== 'undefined') {
- data.email = data.email.toLowerCase().trim();
-
- if (user.email !== data.email) {
- return internalUser.isEmailAvailable(data.email, data.id)
- .then((available) => {
- if (!available) {
- throw new error.ValidationError('Email address already in use - ' + data.email);
- }
-
- return user;
- });
- }
- }
-
- // No change to email:
- return user;
- });
- })
- .then((user) => {
- if (user.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id);
- }
-
- data.avatar = gravatar.url(data.email || user.email, {default: 'mm'});
-
- return userModel
- .query()
- .patchAndFetchById(user.id, data)
- .then(utils.omitRow(omissions()));
- })
- .then(() => {
- return internalUser.get(access, {id: data.id});
- })
- .then((user) => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'user',
- object_id: user.id,
- meta: data
- })
- .then(() => {
- return user;
- });
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} [data]
- * @param {Integer} [data.id] Defaults to the token user
- * @param {Array} [data.expand]
- * @param {Array} [data.omit]
- * @return {Promise}
- */
- get: (access, data) => {
- if (typeof data === 'undefined') {
- data = {};
- }
-
- if (typeof data.id === 'undefined' || !data.id) {
- data.id = access.token.getUserId(0);
- }
-
- return access.can('users:get', data.id)
- .then(() => {
- let query = userModel
- .query()
- .where('is_deleted', 0)
- .andWhere('id', data.id)
- .allowGraph('[permissions]')
- .first();
-
- if (typeof data.expand !== 'undefined' && data.expand !== null) {
- query.withGraphFetched('[' + data.expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRow(omissions()));
- })
- .then((row) => {
- if (!row || !row.id) {
- throw new error.ItemNotFoundError(data.id);
- }
- // Custom omissions
- if (typeof data.omit !== 'undefined' && data.omit !== null) {
- row = _.omit(row, data.omit);
- }
- return row;
- });
- },
-
- /**
- * Checks if an email address is available, but if a user_id is supplied, it will ignore checking
- * against that user.
- *
- * @param email
- * @param user_id
- */
- isEmailAvailable: (email, user_id) => {
- let query = userModel
- .query()
- .where('email', '=', email.toLowerCase().trim())
- .where('is_deleted', 0)
- .first();
-
- if (typeof user_id !== 'undefined') {
- query.where('id', '!=', user_id);
- }
-
- return query
- .then((user) => {
- return !user;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Integer} data.id
- * @param {String} [data.reason]
- * @returns {Promise}
- */
- delete: (access, data) => {
- return access.can('users:delete', data.id)
- .then(() => {
- return internalUser.get(access, {id: data.id});
- })
- .then((user) => {
- if (!user) {
- throw new error.ItemNotFoundError(data.id);
- }
-
- // Make sure user can't delete themselves
- if (user.id === access.token.getUserId(0)) {
- throw new error.PermissionError('You cannot delete yourself.');
- }
-
- return userModel
- .query()
- .where('id', user.id)
- .patch({
- is_deleted: 1
- })
- .then(() => {
- // Add to audit log
- return internalAuditLog.add(access, {
- action: 'deleted',
- object_type: 'user',
- object_id: user.id,
- meta: _.omit(user, omissions())
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * This will only count the users
- *
- * @param {Access} access
- * @param {String} [search_query]
- * @returns {*}
- */
- getCount: (access, search_query) => {
- return access.can('users:list')
- .then(() => {
- let query = userModel
- .query()
- .count('id as count')
- .where('is_deleted', 0)
- .first();
-
- // Query is used for searching
- if (typeof search_query === 'string') {
- query.where(function () {
- this.where('user.name', 'like', '%' + search_query + '%')
- .orWhere('user.email', 'like', '%' + search_query + '%');
- });
- }
-
- return query;
- })
- .then((row) => {
- return parseInt(row.count, 10);
- });
- },
-
- /**
- * All users
- *
- * @param {Access} access
- * @param {Array} [expand]
- * @param {String} [search_query]
- * @returns {Promise}
- */
- getAll: (access, expand, search_query) => {
- return access.can('users:list')
- .then(() => {
- let query = userModel
- .query()
- .where('is_deleted', 0)
- .groupBy('id')
- .allowGraph('[permissions]')
- .orderBy('name', 'ASC');
-
- // Query is used for searching
- if (typeof search_query === 'string') {
- query.where(function () {
- this.where('name', 'like', '%' + search_query + '%')
- .orWhere('email', 'like', '%' + search_query + '%');
- });
- }
-
- if (typeof expand !== 'undefined' && expand !== null) {
- query.withGraphFetched('[' + expand.join(', ') + ']');
- }
-
- return query.then(utils.omitRows(omissions()));
- });
- },
-
- /**
- * @param {Access} access
- * @param {Integer} [id_requested]
- * @returns {[String]}
- */
- getUserOmisionsByAccess: (access, id_requested) => {
- let response = []; // Admin response
-
- if (!access.token.hasScope('admin') && access.token.getUserId(0) !== id_requested) {
- response = ['roles', 'is_deleted']; // Restricted response
- }
-
- return response;
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Integer} data.id
- * @param {String} data.type
- * @param {String} data.secret
- * @return {Promise}
- */
- setPassword: (access, data) => {
- return access.can('users:password', data.id)
- .then(() => {
- return internalUser.get(access, {id: data.id});
- })
- .then((user) => {
- if (user.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id);
- }
-
- if (user.id === access.token.getUserId(0)) {
- // they're setting their own password. Make sure their current password is correct
- if (typeof data.current === 'undefined' || !data.current) {
- throw new error.ValidationError('Current password was not supplied');
- }
-
- return internalToken.getTokenFromEmail({
- identity: user.email,
- secret: data.current
- })
- .then(() => {
- return user;
- });
- }
-
- return user;
- })
- .then((user) => {
- // Get auth, patch if it exists
- return authModel
- .query()
- .where('user_id', user.id)
- .andWhere('type', data.type)
- .first()
- .then((existing_auth) => {
- if (existing_auth) {
- // patch
- return authModel
- .query()
- .where('user_id', user.id)
- .andWhere('type', data.type)
- .patch({
- type: data.type, // This is required for the model to encrypt on save
- secret: data.secret
- });
- } else {
- // insert
- return authModel
- .query()
- .insert({
- user_id: user.id,
- type: data.type,
- secret: data.secret,
- meta: {}
- });
- }
- })
- .then(() => {
- // Add to Audit Log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'user',
- object_id: user.id,
- meta: {
- name: user.name,
- password_changed: true,
- auth_type: data.type
- }
- });
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @return {Promise}
- */
- setPermissions: (access, data) => {
- return access.can('users:permissions', data.id)
- .then(() => {
- return internalUser.get(access, {id: data.id});
- })
- .then((user) => {
- if (user.id !== data.id) {
- // Sanity check that something crazy hasn't happened
- throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id);
- }
-
- return user;
- })
- .then((user) => {
- // Get perms row, patch if it exists
- return userPermissionModel
- .query()
- .where('user_id', user.id)
- .first()
- .then((existing_auth) => {
- if (existing_auth) {
- // patch
- return userPermissionModel
- .query()
- .where('user_id', user.id)
- .patchAndFetchById(existing_auth.id, _.assign({user_id: user.id}, data));
- } else {
- // insert
- return userPermissionModel
- .query()
- .insertAndFetch(_.assign({user_id: user.id}, data));
- }
- })
- .then((permissions) => {
- // Add to Audit Log
- return internalAuditLog.add(access, {
- action: 'updated',
- object_type: 'user',
- object_id: user.id,
- meta: {
- name: user.name,
- permissions: permissions
- }
- });
-
- });
- })
- .then(() => {
- return true;
- });
- },
-
- /**
- * @param {Access} access
- * @param {Object} data
- * @param {Integer} data.id
- */
- loginAs: (access, data) => {
- return access.can('users:loginas', data.id)
- .then(() => {
- return internalUser.get(access, data);
- })
- .then((user) => {
- return internalToken.getTokenFromUser(user);
- });
- }
-};
-
-module.exports = internalUser;
diff --git a/backend/knexfile.js b/backend/knexfile.js
deleted file mode 100644
index 607552f6..00000000
--- a/backend/knexfile.js
+++ /dev/null
@@ -1,19 +0,0 @@
-module.exports = {
- development: {
- client: 'mysql2',
- migrations: {
- tableName: 'migrations',
- stub: 'lib/migrate_template.js',
- directory: 'migrations'
- }
- },
-
- production: {
- client: 'mysql2',
- migrations: {
- tableName: 'migrations',
- stub: 'lib/migrate_template.js',
- directory: 'migrations'
- }
- }
-};
diff --git a/backend/lib/access.js b/backend/lib/access.js
deleted file mode 100644
index 0e658a65..00000000
--- a/backend/lib/access.js
+++ /dev/null
@@ -1,307 +0,0 @@
-/**
- * Some Notes: This is a friggin complicated piece of code.
- *
- * "scope" in this file means "where did this token come from and what is using it", so 99% of the time
- * the "scope" is going to be "user" because it would be a user token. This is not to be confused with
- * the "role" which could be "user" or "admin". The scope in fact, could be "worker" or anything else.
- *
- *
- */
-
-const _ = require('lodash');
-const logger = require('../logger').access;
-const Ajv = require('ajv/dist/2020');
-const error = require('./error');
-const userModel = require('../models/user');
-const proxyHostModel = require('../models/proxy_host');
-const TokenModel = require('../models/token');
-const roleSchema = require('./access/roles.json');
-const permsSchema = require('./access/permissions.json');
-
-module.exports = function (token_string) {
- let Token = new TokenModel();
- let token_data = null;
- let initialised = false;
- let object_cache = {};
- let allow_internal_access = false;
- let user_roles = [];
- let permissions = {};
-
- /**
- * Loads the Token object from the token string
- *
- * @returns {Promise}
- */
- this.init = () => {
- return new Promise((resolve, reject) => {
- if (initialised) {
- resolve();
- } else if (!token_string) {
- reject(new error.PermissionError('Permission Denied'));
- } else {
- resolve(Token.load(token_string)
- .then((data) => {
- token_data = data;
-
- // At this point we need to load the user from the DB and make sure they:
- // - exist (and not soft deleted)
- // - still have the appropriate scopes for this token
- // This is only required when the User ID is supplied or if the token scope has `user`
-
- if (token_data.attrs.id || (typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'user') !== -1)) {
- // Has token user id or token user scope
- return userModel
- .query()
- .where('id', token_data.attrs.id)
- .andWhere('is_deleted', 0)
- .andWhere('is_disabled', 0)
- .allowGraph('[permissions]')
- .withGraphFetched('[permissions]')
- .first()
- .then((user) => {
- if (user) {
- // make sure user has all scopes of the token
- // The `user` role is not added against the user row, so we have to just add it here to get past this check.
- user.roles.push('user');
-
- let is_ok = true;
- _.forEach(token_data.scope, (scope_item) => {
- if (_.indexOf(user.roles, scope_item) === -1) {
- is_ok = false;
- }
- });
-
- if (!is_ok) {
- throw new error.AuthError('Invalid token scope for User');
- } else {
- initialised = true;
- user_roles = user.roles;
- permissions = user.permissions;
- }
-
- } else {
- throw new error.AuthError('User cannot be loaded for Token');
- }
- });
- } else {
- initialised = true;
- }
- }));
- }
- });
- };
-
- /**
- * Fetches the object ids from the database, only once per object type, for this token.
- * This only applies to USER token scopes, as all other tokens are not really bound
- * by object scopes
- *
- * @param {String} object_type
- * @returns {Promise}
- */
- this.loadObjects = (object_type) => {
- return new Promise((resolve, reject) => {
- if (Token.hasScope('user')) {
- if (typeof token_data.attrs.id === 'undefined' || !token_data.attrs.id) {
- reject(new error.AuthError('User Token supplied without a User ID'));
- } else {
- let token_user_id = token_data.attrs.id ? token_data.attrs.id : 0;
- let query;
-
- if (typeof object_cache[object_type] === 'undefined') {
- switch (object_type) {
-
- // USERS - should only return yourself
- case 'users':
- resolve(token_user_id ? [token_user_id] : []);
- break;
-
- // Proxy Hosts
- case 'proxy_hosts':
- query = proxyHostModel
- .query()
- .select('id')
- .andWhere('is_deleted', 0);
-
- if (permissions.visibility === 'user') {
- query.andWhere('owner_user_id', token_user_id);
- }
-
- resolve(query
- .then((rows) => {
- let result = [];
- _.forEach(rows, (rule_row) => {
- result.push(rule_row.id);
- });
-
- // enum should not have less than 1 item
- if (!result.length) {
- result.push(0);
- }
-
- return result;
- })
- );
- break;
-
- // DEFAULT: null
- default:
- resolve(null);
- break;
- }
- } else {
- resolve(object_cache[object_type]);
- }
- }
- } else {
- resolve(null);
- }
- })
- .then((objects) => {
- object_cache[object_type] = objects;
- return objects;
- });
- };
-
- /**
- * Creates a schema object on the fly with the IDs and other values required to be checked against the permissionSchema
- *
- * @param {String} permission_label
- * @returns {Object}
- */
- this.getObjectSchema = (permission_label) => {
- let base_object_type = permission_label.split(':').shift();
-
- let schema = {
- $id: 'objects',
- description: 'Actor Properties',
- type: 'object',
- additionalProperties: false,
- properties: {
- user_id: {
- anyOf: [
- {
- type: 'number',
- enum: [Token.get('attrs').id]
- }
- ]
- },
- scope: {
- type: 'string',
- pattern: '^' + Token.get('scope') + '$'
- }
- }
- };
-
- return this.loadObjects(base_object_type)
- .then((object_result) => {
- if (typeof object_result === 'object' && object_result !== null) {
- schema.properties[base_object_type] = {
- type: 'number',
- enum: object_result,
- minimum: 1
- };
- } else {
- schema.properties[base_object_type] = {
- type: 'number',
- minimum: 1
- };
- }
-
- return schema;
- });
- };
-
- return {
-
- token: Token,
-
- /**
- *
- * @param {Boolean} [allow_internal]
- * @returns {Promise}
- */
- load: (allow_internal) => {
- return new Promise(function (resolve/*, reject*/) {
- if (token_string) {
- resolve(Token.load(token_string));
- } else {
- allow_internal_access = allow_internal;
- resolve(allow_internal_access || null);
- }
- });
- },
-
- reloadObjects: this.loadObjects,
-
- /**
- *
- * @param {String} permission
- * @param {*} [data]
- * @returns {Promise}
- */
- can: (permission, data) => {
- if (allow_internal_access === true) {
- return Promise.resolve(true);
- //return true;
- } else {
- return this.init()
- .then(() => {
- // Initialised, token decoded ok
- return this.getObjectSchema(permission)
- .then((objectSchema) => {
- const data_schema = {
- [permission]: {
- data: data,
- scope: Token.get('scope'),
- roles: user_roles,
- permission_visibility: permissions.visibility,
- permission_proxy_hosts: permissions.proxy_hosts,
- permission_redirection_hosts: permissions.redirection_hosts,
- permission_dead_hosts: permissions.dead_hosts,
- permission_streams: permissions.streams,
- permission_access_lists: permissions.access_lists,
- permission_certificates: permissions.certificates
- }
- };
-
- let permissionSchema = {
- $async: true,
- $id: 'permissions',
- type: 'object',
- additionalProperties: false,
- properties: {}
- };
-
- permissionSchema.properties[permission] = require('./access/' + permission.replace(/:/gim, '-') + '.json');
-
- const ajv = new Ajv({
- verbose: true,
- allErrors: true,
- breakOnError: true,
- coerceTypes: true,
- schemas: [
- roleSchema,
- permsSchema,
- objectSchema,
- permissionSchema
- ]
- });
-
- return ajv.validate('permissions', data_schema)
- .then(() => {
- return data_schema[permission];
- });
- });
- })
- .catch((err) => {
- err.permission = permission;
- err.permission_data = data;
- logger.error(permission, data, err.message);
-
- throw new error.PermissionError('Permission Denied', err);
- });
- }
- }
- };
-};
diff --git a/backend/lib/access/access_lists-create.json b/backend/lib/access/access_lists-create.json
deleted file mode 100644
index 5a16a864..00000000
--- a/backend/lib/access/access_lists-create.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_access_lists", "roles"],
- "properties": {
- "permission_access_lists": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/access_lists-delete.json b/backend/lib/access/access_lists-delete.json
deleted file mode 100644
index 5a16a864..00000000
--- a/backend/lib/access/access_lists-delete.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_access_lists", "roles"],
- "properties": {
- "permission_access_lists": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/access_lists-get.json b/backend/lib/access/access_lists-get.json
deleted file mode 100644
index 8f6dd8cc..00000000
--- a/backend/lib/access/access_lists-get.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_access_lists", "roles"],
- "properties": {
- "permission_access_lists": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/access_lists-list.json b/backend/lib/access/access_lists-list.json
deleted file mode 100644
index 8f6dd8cc..00000000
--- a/backend/lib/access/access_lists-list.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_access_lists", "roles"],
- "properties": {
- "permission_access_lists": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/access_lists-update.json b/backend/lib/access/access_lists-update.json
deleted file mode 100644
index 5a16a864..00000000
--- a/backend/lib/access/access_lists-update.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_access_lists", "roles"],
- "properties": {
- "permission_access_lists": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/auditlog-list.json b/backend/lib/access/auditlog-list.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/auditlog-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/certificates-create.json b/backend/lib/access/certificates-create.json
deleted file mode 100644
index bcdf6674..00000000
--- a/backend/lib/access/certificates-create.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_certificates", "roles"],
- "properties": {
- "permission_certificates": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/certificates-delete.json b/backend/lib/access/certificates-delete.json
deleted file mode 100644
index bcdf6674..00000000
--- a/backend/lib/access/certificates-delete.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_certificates", "roles"],
- "properties": {
- "permission_certificates": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/certificates-get.json b/backend/lib/access/certificates-get.json
deleted file mode 100644
index 9ccfa4f1..00000000
--- a/backend/lib/access/certificates-get.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_certificates", "roles"],
- "properties": {
- "permission_certificates": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/certificates-list.json b/backend/lib/access/certificates-list.json
deleted file mode 100644
index 9ccfa4f1..00000000
--- a/backend/lib/access/certificates-list.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_certificates", "roles"],
- "properties": {
- "permission_certificates": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/certificates-update.json b/backend/lib/access/certificates-update.json
deleted file mode 100644
index bcdf6674..00000000
--- a/backend/lib/access/certificates-update.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_certificates", "roles"],
- "properties": {
- "permission_certificates": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/dead_hosts-create.json b/backend/lib/access/dead_hosts-create.json
deleted file mode 100644
index a276c681..00000000
--- a/backend/lib/access/dead_hosts-create.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_dead_hosts", "roles"],
- "properties": {
- "permission_dead_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/dead_hosts-delete.json b/backend/lib/access/dead_hosts-delete.json
deleted file mode 100644
index a276c681..00000000
--- a/backend/lib/access/dead_hosts-delete.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_dead_hosts", "roles"],
- "properties": {
- "permission_dead_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/dead_hosts-get.json b/backend/lib/access/dead_hosts-get.json
deleted file mode 100644
index 87aa12e7..00000000
--- a/backend/lib/access/dead_hosts-get.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_dead_hosts", "roles"],
- "properties": {
- "permission_dead_hosts": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/dead_hosts-list.json b/backend/lib/access/dead_hosts-list.json
deleted file mode 100644
index 87aa12e7..00000000
--- a/backend/lib/access/dead_hosts-list.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_dead_hosts", "roles"],
- "properties": {
- "permission_dead_hosts": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/dead_hosts-update.json b/backend/lib/access/dead_hosts-update.json
deleted file mode 100644
index a276c681..00000000
--- a/backend/lib/access/dead_hosts-update.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_dead_hosts", "roles"],
- "properties": {
- "permission_dead_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/permissions.json b/backend/lib/access/permissions.json
deleted file mode 100644
index e7a82ece..00000000
--- a/backend/lib/access/permissions.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "$id": "perms",
- "definitions": {
- "view": {
- "type": "string",
- "pattern": "^(view|manage)$"
- },
- "manage": {
- "type": "string",
- "pattern": "^(manage)$"
- }
- }
-}
diff --git a/backend/lib/access/proxy_hosts-create.json b/backend/lib/access/proxy_hosts-create.json
deleted file mode 100644
index 166527a3..00000000
--- a/backend/lib/access/proxy_hosts-create.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_proxy_hosts", "roles"],
- "properties": {
- "permission_proxy_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/proxy_hosts-delete.json b/backend/lib/access/proxy_hosts-delete.json
deleted file mode 100644
index 166527a3..00000000
--- a/backend/lib/access/proxy_hosts-delete.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_proxy_hosts", "roles"],
- "properties": {
- "permission_proxy_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/proxy_hosts-get.json b/backend/lib/access/proxy_hosts-get.json
deleted file mode 100644
index d88e4cff..00000000
--- a/backend/lib/access/proxy_hosts-get.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_proxy_hosts", "roles"],
- "properties": {
- "permission_proxy_hosts": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/proxy_hosts-list.json b/backend/lib/access/proxy_hosts-list.json
deleted file mode 100644
index d88e4cff..00000000
--- a/backend/lib/access/proxy_hosts-list.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_proxy_hosts", "roles"],
- "properties": {
- "permission_proxy_hosts": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/proxy_hosts-update.json b/backend/lib/access/proxy_hosts-update.json
deleted file mode 100644
index 166527a3..00000000
--- a/backend/lib/access/proxy_hosts-update.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_proxy_hosts", "roles"],
- "properties": {
- "permission_proxy_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/redirection_hosts-create.json b/backend/lib/access/redirection_hosts-create.json
deleted file mode 100644
index 342babc8..00000000
--- a/backend/lib/access/redirection_hosts-create.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_redirection_hosts", "roles"],
- "properties": {
- "permission_redirection_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/redirection_hosts-delete.json b/backend/lib/access/redirection_hosts-delete.json
deleted file mode 100644
index 342babc8..00000000
--- a/backend/lib/access/redirection_hosts-delete.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_redirection_hosts", "roles"],
- "properties": {
- "permission_redirection_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/redirection_hosts-get.json b/backend/lib/access/redirection_hosts-get.json
deleted file mode 100644
index ba229206..00000000
--- a/backend/lib/access/redirection_hosts-get.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_redirection_hosts", "roles"],
- "properties": {
- "permission_redirection_hosts": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/redirection_hosts-list.json b/backend/lib/access/redirection_hosts-list.json
deleted file mode 100644
index ba229206..00000000
--- a/backend/lib/access/redirection_hosts-list.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_redirection_hosts", "roles"],
- "properties": {
- "permission_redirection_hosts": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/redirection_hosts-update.json b/backend/lib/access/redirection_hosts-update.json
deleted file mode 100644
index 342babc8..00000000
--- a/backend/lib/access/redirection_hosts-update.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_redirection_hosts", "roles"],
- "properties": {
- "permission_redirection_hosts": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/reports-hosts.json b/backend/lib/access/reports-hosts.json
deleted file mode 100644
index dbc9e0c0..00000000
--- a/backend/lib/access/reports-hosts.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/user"
- }
- ]
-}
diff --git a/backend/lib/access/roles.json b/backend/lib/access/roles.json
deleted file mode 100644
index c97313da..00000000
--- a/backend/lib/access/roles.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "$id": "roles",
- "definitions": {
- "admin": {
- "type": "object",
- "required": ["scope", "roles"],
- "properties": {
- "scope": {
- "type": "array",
- "contains": {
- "type": "string",
- "pattern": "^user$"
- }
- },
- "roles": {
- "type": "array",
- "contains": {
- "type": "string",
- "pattern": "^admin$"
- }
- }
- }
- },
- "user": {
- "type": "object",
- "required": ["scope"],
- "properties": {
- "scope": {
- "type": "array",
- "contains": {
- "type": "string",
- "pattern": "^user$"
- }
- }
- }
- }
- }
-}
diff --git a/backend/lib/access/settings-get.json b/backend/lib/access/settings-get.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/settings-get.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/settings-list.json b/backend/lib/access/settings-list.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/settings-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/settings-update.json b/backend/lib/access/settings-update.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/settings-update.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/streams-create.json b/backend/lib/access/streams-create.json
deleted file mode 100644
index fbeb1cc9..00000000
--- a/backend/lib/access/streams-create.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_streams", "roles"],
- "properties": {
- "permission_streams": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/streams-delete.json b/backend/lib/access/streams-delete.json
deleted file mode 100644
index fbeb1cc9..00000000
--- a/backend/lib/access/streams-delete.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_streams", "roles"],
- "properties": {
- "permission_streams": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/streams-get.json b/backend/lib/access/streams-get.json
deleted file mode 100644
index 7e996287..00000000
--- a/backend/lib/access/streams-get.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_streams", "roles"],
- "properties": {
- "permission_streams": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/streams-list.json b/backend/lib/access/streams-list.json
deleted file mode 100644
index 7e996287..00000000
--- a/backend/lib/access/streams-list.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_streams", "roles"],
- "properties": {
- "permission_streams": {
- "$ref": "perms#/definitions/view"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/streams-update.json b/backend/lib/access/streams-update.json
deleted file mode 100644
index fbeb1cc9..00000000
--- a/backend/lib/access/streams-update.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["permission_streams", "roles"],
- "properties": {
- "permission_streams": {
- "$ref": "perms#/definitions/manage"
- },
- "roles": {
- "type": "array",
- "items": {
- "type": "string",
- "enum": ["user"]
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/users-create.json b/backend/lib/access/users-create.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/users-create.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/users-delete.json b/backend/lib/access/users-delete.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/users-delete.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/users-get.json b/backend/lib/access/users-get.json
deleted file mode 100644
index 2a2f0423..00000000
--- a/backend/lib/access/users-get.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["data", "scope"],
- "properties": {
- "data": {
- "$ref": "objects#/properties/users"
- },
- "scope": {
- "type": "array",
- "contains": {
- "type": "string",
- "pattern": "^user$"
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/users-list.json b/backend/lib/access/users-list.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/users-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/users-loginas.json b/backend/lib/access/users-loginas.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/users-loginas.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/users-password.json b/backend/lib/access/users-password.json
deleted file mode 100644
index 2a2f0423..00000000
--- a/backend/lib/access/users-password.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["data", "scope"],
- "properties": {
- "data": {
- "$ref": "objects#/properties/users"
- },
- "scope": {
- "type": "array",
- "contains": {
- "type": "string",
- "pattern": "^user$"
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/access/users-permissions.json b/backend/lib/access/users-permissions.json
deleted file mode 100644
index aeadc94b..00000000
--- a/backend/lib/access/users-permissions.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- }
- ]
-}
diff --git a/backend/lib/access/users-update.json b/backend/lib/access/users-update.json
deleted file mode 100644
index 2a2f0423..00000000
--- a/backend/lib/access/users-update.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "anyOf": [
- {
- "$ref": "roles#/definitions/admin"
- },
- {
- "type": "object",
- "required": ["data", "scope"],
- "properties": {
- "data": {
- "$ref": "objects#/properties/users"
- },
- "scope": {
- "type": "array",
- "contains": {
- "type": "string",
- "pattern": "^user$"
- }
- }
- }
- }
- ]
-}
diff --git a/backend/lib/certbot.js b/backend/lib/certbot.js
deleted file mode 100644
index 96d94710..00000000
--- a/backend/lib/certbot.js
+++ /dev/null
@@ -1,85 +0,0 @@
-const dnsPlugins = require('../global/certbot-dns-plugins.json');
-const utils = require('./utils');
-const error = require('./error');
-const logger = require('../logger').certbot;
-const batchflow = require('batchflow');
-
-const CERTBOT_VERSION_REPLACEMENT = '$(certbot --version | grep -Eo \'[0-9](\\.[0-9]+)+\')';
-
-const certbot = {
-
- /**
- * @param {array} pluginKeys
- */
- installPlugins: async (pluginKeys) => {
- let hasErrors = false;
-
- return new Promise((resolve, reject) => {
- if (pluginKeys.length === 0) {
- resolve();
- return;
- }
-
- batchflow(pluginKeys).sequential()
- .each((_i, pluginKey, next) => {
- certbot.installPlugin(pluginKey)
- .then(() => {
- next();
- })
- .catch((err) => {
- hasErrors = true;
- next(err);
- });
- })
- .error((err) => {
- logger.error(err.message);
- })
- .end(() => {
- if (hasErrors) {
- reject(new error.CommandError('Some plugins failed to install. Please check the logs above', 1));
- } else {
- resolve();
- }
- });
- });
- },
-
- /**
- * Installs a cerbot plugin given the key for the object from
- * ../global/certbot-dns-plugins.json
- *
- * @param {string} pluginKey
- * @returns {Object}
- */
- installPlugin: async (pluginKey) => {
- if (typeof dnsPlugins[pluginKey] === 'undefined') {
- // throw Error(`Certbot plugin ${pluginKey} not found`);
- throw new error.ItemNotFoundError(pluginKey);
- }
-
- const plugin = dnsPlugins[pluginKey];
- logger.start(`Installing ${pluginKey}...`);
-
- plugin.version = plugin.version.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
- plugin.dependencies = plugin.dependencies.replace(/{{certbot-version}}/g, CERTBOT_VERSION_REPLACEMENT);
-
- // SETUPTOOLS_USE_DISTUTILS is required for certbot plugins to install correctly
- // in new versions of Python
- let env = Object.assign({}, process.env, {SETUPTOOLS_USE_DISTUTILS: 'stdlib'});
- if (typeof plugin.env === 'object') {
- env = Object.assign(env, plugin.env);
- }
-
- const cmd = `. /opt/certbot/bin/activate && pip install --no-cache-dir ${plugin.dependencies} ${plugin.package_name}${plugin.version} && deactivate`;
- return utils.exec(cmd, {env})
- .then((result) => {
- logger.complete(`Installed ${pluginKey}`);
- return result;
- })
- .catch((err) => {
- throw err;
- });
- },
-};
-
-module.exports = certbot;
diff --git a/backend/lib/config.js b/backend/lib/config.js
deleted file mode 100644
index 23184f3e..00000000
--- a/backend/lib/config.js
+++ /dev/null
@@ -1,237 +0,0 @@
-const fs = require('fs');
-const NodeRSA = require('node-rsa');
-const logger = require('../logger').global;
-
-const keysFile = '/data/keys.json';
-const mysqlEngine = 'mysql2';
-const postgresEngine = 'pg';
-const sqliteClientName = 'sqlite3';
-
-let instance = null;
-
-// 1. Load from config file first (not recommended anymore)
-// 2. Use config env variables next
-const configure = () => {
- const filename = (process.env.NODE_CONFIG_DIR || './config') + '/' + (process.env.NODE_ENV || 'default') + '.json';
- if (fs.existsSync(filename)) {
- let configData;
- try {
- configData = require(filename);
- } catch (_) {
- // do nothing
- }
-
- if (configData && configData.database) {
- logger.info(`Using configuration from file: ${filename}`);
- instance = configData;
- instance.keys = getKeys();
- return;
- }
- }
-
- const envMysqlHost = process.env.DB_MYSQL_HOST || null;
- const envMysqlUser = process.env.DB_MYSQL_USER || null;
- const envMysqlName = process.env.DB_MYSQL_NAME || null;
- if (envMysqlHost && envMysqlUser && envMysqlName) {
- // we have enough mysql creds to go with mysql
- logger.info('Using MySQL configuration');
- instance = {
- database: {
- engine: mysqlEngine,
- host: envMysqlHost,
- port: process.env.DB_MYSQL_PORT || 3306,
- user: envMysqlUser,
- password: process.env.DB_MYSQL_PASSWORD,
- name: envMysqlName,
- },
- keys: getKeys(),
- };
- return;
- }
-
- const envPostgresHost = process.env.DB_POSTGRES_HOST || null;
- const envPostgresUser = process.env.DB_POSTGRES_USER || null;
- const envPostgresName = process.env.DB_POSTGRES_NAME || null;
- if (envPostgresHost && envPostgresUser && envPostgresName) {
- // we have enough postgres creds to go with postgres
- logger.info('Using Postgres configuration');
- instance = {
- database: {
- engine: postgresEngine,
- host: envPostgresHost,
- port: process.env.DB_POSTGRES_PORT || 5432,
- user: envPostgresUser,
- password: process.env.DB_POSTGRES_PASSWORD,
- name: envPostgresName,
- },
- keys: getKeys(),
- };
- return;
- }
-
- const envSqliteFile = process.env.DB_SQLITE_FILE || '/data/database.sqlite';
- logger.info(`Using Sqlite: ${envSqliteFile}`);
- instance = {
- database: {
- engine: 'knex-native',
- knex: {
- client: sqliteClientName,
- connection: {
- filename: envSqliteFile
- },
- useNullAsDefault: true
- }
- },
- keys: getKeys(),
- };
-};
-
-const getKeys = () => {
- // Get keys from file
- if (!fs.existsSync(keysFile)) {
- generateKeys();
- } else if (process.env.DEBUG) {
- logger.info('Keys file exists OK');
- }
- try {
- return require(keysFile);
- } catch (err) {
- logger.error('Could not read JWT key pair from config file: ' + keysFile, err);
- process.exit(1);
- }
-};
-
-const generateKeys = () => {
- logger.info('Creating a new JWT key pair...');
- // Now create the keys and save them in the config.
- const key = new NodeRSA({ b: 2048 });
- key.generateKeyPair();
-
- const keys = {
- key: key.exportKey('private').toString(),
- pub: key.exportKey('public').toString(),
- };
-
- // Write keys config
- try {
- fs.writeFileSync(keysFile, JSON.stringify(keys, null, 2));
- } catch (err) {
- logger.error('Could not write JWT key pair to config file: ' + keysFile + ': ' + err.message);
- process.exit(1);
- }
- logger.info('Wrote JWT key pair to config file: ' + keysFile);
-};
-
-module.exports = {
-
- /**
- *
- * @param {string} key ie: 'database' or 'database.engine'
- * @returns {boolean}
- */
- has: function(key) {
- instance === null && configure();
- const keys = key.split('.');
- let level = instance;
- let has = true;
- keys.forEach((keyItem) =>{
- if (typeof level[keyItem] === 'undefined') {
- has = false;
- } else {
- level = level[keyItem];
- }
- });
-
- return has;
- },
-
- /**
- * Gets a specific key from the top level
- *
- * @param {string} key
- * @returns {*}
- */
- get: function (key) {
- instance === null && configure();
- if (key && typeof instance[key] !== 'undefined') {
- return instance[key];
- }
- return instance;
- },
-
- /**
- * Is this a sqlite configuration?
- *
- * @returns {boolean}
- */
- isSqlite: function () {
- instance === null && configure();
- return instance.database.knex && instance.database.knex.client === sqliteClientName;
- },
-
- /**
- * Is this a mysql configuration?
- *
- * @returns {boolean}
- */
- isMysql: function () {
- instance === null && configure();
- return instance.database.engine === mysqlEngine;
- },
-
- /**
- * Is this a postgres configuration?
- *
- * @returns {boolean}
- */
- isPostgres: function () {
- instance === null && configure();
- return instance.database.engine === postgresEngine;
- },
-
- /**
- * Are we running in debug mdoe?
- *
- * @returns {boolean}
- */
- debug: function () {
- return !!process.env.DEBUG;
- },
-
- /**
- * Returns a public key
- *
- * @returns {string}
- */
- getPublicKey: function () {
- instance === null && configure();
- return instance.keys.pub;
- },
-
- /**
- * Returns a private key
- *
- * @returns {string}
- */
- getPrivateKey: function () {
- instance === null && configure();
- return instance.keys.key;
- },
-
- /**
- * @returns {boolean}
- */
- useLetsencryptStaging: function () {
- return !!process.env.LE_STAGING;
- },
-
- /**
- * @returns {string|null}
- */
- useLetsencryptServer: function () {
- if (process.env.LE_SERVER) {
- return process.env.LE_SERVER;
- }
- return null;
- }
-};
diff --git a/backend/lib/error.js b/backend/lib/error.js
deleted file mode 100644
index 413d6a7d..00000000
--- a/backend/lib/error.js
+++ /dev/null
@@ -1,99 +0,0 @@
-const _ = require('lodash');
-const util = require('util');
-
-module.exports = {
-
- PermissionError: function (message, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = 'Permission Denied';
- this.public = true;
- this.status = 403;
- },
-
- ItemNotFoundError: function (id, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = 'Item Not Found - ' + id;
- this.public = true;
- this.status = 404;
- },
-
- AuthError: function (message, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = message;
- this.public = true;
- this.status = 401;
- },
-
- InternalError: function (message, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = message;
- this.status = 500;
- this.public = false;
- },
-
- InternalValidationError: function (message, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = message;
- this.status = 400;
- this.public = false;
- },
-
- ConfigurationError: function (message, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = message;
- this.status = 400;
- this.public = true;
- },
-
- CacheError: function (message, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.message = message;
- this.previous = previous;
- this.status = 500;
- this.public = false;
- },
-
- ValidationError: function (message, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = message;
- this.public = true;
- this.status = 400;
- },
-
- AssertionFailedError: function (message, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = message;
- this.public = false;
- this.status = 400;
- },
-
- CommandError: function (stdErr, code, previous) {
- Error.captureStackTrace(this, this.constructor);
- this.name = this.constructor.name;
- this.previous = previous;
- this.message = stdErr;
- this.code = code;
- this.public = false;
- },
-};
-
-_.forEach(module.exports, function (error) {
- util.inherits(error, Error);
-});
diff --git a/backend/lib/express/cors.js b/backend/lib/express/cors.js
deleted file mode 100644
index 6d5b8b5f..00000000
--- a/backend/lib/express/cors.js
+++ /dev/null
@@ -1,16 +0,0 @@
-module.exports = function (req, res, next) {
- if (req.headers.origin) {
- res.set({
- 'Access-Control-Allow-Origin': req.headers.origin,
- 'Access-Control-Allow-Credentials': true,
- 'Access-Control-Allow-Methods': 'OPTIONS, GET, POST',
- 'Access-Control-Allow-Headers': 'Content-Type, Cache-Control, Pragma, Expires, Authorization, X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit',
- 'Access-Control-Max-Age': 5 * 60,
- 'Access-Control-Expose-Headers': 'X-Dataset-Total, X-Dataset-Offset, X-Dataset-Limit'
- });
- next();
- } else {
- // No origin
- next();
- }
-};
diff --git a/backend/lib/express/jwt-decode.js b/backend/lib/express/jwt-decode.js
deleted file mode 100644
index 17edccec..00000000
--- a/backend/lib/express/jwt-decode.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const Access = require('../access');
-
-module.exports = () => {
- return function (req, res, next) {
- res.locals.access = null;
- let access = new Access(res.locals.token || null);
- access.load()
- .then(() => {
- res.locals.access = access;
- next();
- })
- .catch(next);
- };
-};
-
diff --git a/backend/lib/express/jwt.js b/backend/lib/express/jwt.js
deleted file mode 100644
index 44aa3693..00000000
--- a/backend/lib/express/jwt.js
+++ /dev/null
@@ -1,13 +0,0 @@
-module.exports = function () {
- return function (req, res, next) {
- if (req.headers.authorization) {
- let parts = req.headers.authorization.split(' ');
-
- if (parts && parts[0] === 'Bearer' && parts[1]) {
- res.locals.token = parts[1];
- }
- }
-
- next();
- };
-};
diff --git a/backend/lib/express/pagination.js b/backend/lib/express/pagination.js
deleted file mode 100644
index 24ffa58d..00000000
--- a/backend/lib/express/pagination.js
+++ /dev/null
@@ -1,55 +0,0 @@
-let _ = require('lodash');
-
-module.exports = function (default_sort, default_offset, default_limit, max_limit) {
-
- /**
- * This will setup the req query params with filtered data and defaults
- *
- * sort will be an array of fields and their direction
- * offset will be an int, defaulting to zero if no other default supplied
- * limit will be an int, defaulting to 50 if no other default supplied, and limited to the max if that was supplied
- *
- */
-
- return function (req, res, next) {
-
- req.query.offset = typeof req.query.limit === 'undefined' ? default_offset || 0 : parseInt(req.query.offset, 10);
- req.query.limit = typeof req.query.limit === 'undefined' ? default_limit || 50 : parseInt(req.query.limit, 10);
-
- if (max_limit && req.query.limit > max_limit) {
- req.query.limit = max_limit;
- }
-
- // Sorting
- let sort = typeof req.query.sort === 'undefined' ? default_sort : req.query.sort;
- let myRegexp = /.*\.(asc|desc)$/ig;
- let sort_array = [];
-
- sort = sort.split(',');
- _.map(sort, function (val) {
- let matches = myRegexp.exec(val);
-
- if (matches !== null) {
- let dir = matches[1];
- sort_array.push({
- field: val.substr(0, val.length - (dir.length + 1)),
- dir: dir.toLowerCase()
- });
- } else {
- sort_array.push({
- field: val,
- dir: 'asc'
- });
- }
- });
-
- // Sort will now be in this format:
- // [
- // { field: 'field1', dir: 'asc' },
- // { field: 'field2', dir: 'desc' }
- // ]
-
- req.query.sort = sort_array;
- next();
- };
-};
diff --git a/backend/lib/express/user-id-from-me.js b/backend/lib/express/user-id-from-me.js
deleted file mode 100644
index 4a37a406..00000000
--- a/backend/lib/express/user-id-from-me.js
+++ /dev/null
@@ -1,9 +0,0 @@
-module.exports = (req, res, next) => {
- if (req.params.user_id === 'me' && res.locals.access) {
- req.params.user_id = res.locals.access.token.get('attrs').id;
- } else {
- req.params.user_id = parseInt(req.params.user_id, 10);
- }
-
- next();
-};
diff --git a/backend/lib/helpers.js b/backend/lib/helpers.js
deleted file mode 100644
index ad3df3c2..00000000
--- a/backend/lib/helpers.js
+++ /dev/null
@@ -1,62 +0,0 @@
-const moment = require('moment');
-const {isPostgres} = require('./config');
-const {ref} = require('objection');
-
-module.exports = {
-
- /**
- * Takes an expression such as 30d and returns a moment object of that date in future
- *
- * Key Shorthand
- * ==================
- * years y
- * quarters Q
- * months M
- * weeks w
- * days d
- * hours h
- * minutes m
- * seconds s
- * milliseconds ms
- *
- * @param {String} expression
- * @returns {Object}
- */
- parseDatePeriod: function (expression) {
- let matches = expression.match(/^([0-9]+)(y|Q|M|w|d|h|m|s|ms)$/m);
- if (matches) {
- return moment().add(matches[1], matches[2]);
- }
-
- return null;
- },
-
- convertIntFieldsToBool: function (obj, fields) {
- fields.forEach(function (field) {
- if (typeof obj[field] !== 'undefined') {
- obj[field] = obj[field] === 1;
- }
- });
- return obj;
- },
-
- convertBoolFieldsToInt: function (obj, fields) {
- fields.forEach(function (field) {
- if (typeof obj[field] !== 'undefined') {
- obj[field] = obj[field] ? 1 : 0;
- }
- });
- return obj;
- },
-
- /**
- * Casts a column to json if using postgres
- *
- * @param {string} colName
- * @returns {string|Objection.ReferenceBuilder}
- */
- castJsonIfNeed: function (colName) {
- return isPostgres() ? ref(colName).castText() : colName;
- }
-
-};
diff --git a/backend/lib/migrate_template.js b/backend/lib/migrate_template.js
deleted file mode 100644
index f75f77ef..00000000
--- a/backend/lib/migrate_template.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const migrate_name = 'identifier_for_migrate';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex, Promise) {
-
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- // Create Table example:
-
- /*return knex.schema.createTable('notification', (table) => {
- table.increments().primary();
- table.string('name').notNull();
- table.string('type').notNull();
- table.integer('created_on').notNull();
- table.integer('modified_on').notNull();
- })
- .then(function () {
- logger.info('[' + migrate_name + '] Notification Table created');
- });*/
-
- logger.info('[' + migrate_name + '] Migrating Up Complete');
-
- return Promise.resolve(true);
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.info('[' + migrate_name + '] Migrating Down...');
-
- // Drop table example:
-
- /*return knex.schema.dropTable('notification')
- .then(() => {
- logger.info('[' + migrate_name + '] Notification Table dropped');
- });*/
-
- logger.info('[' + migrate_name + '] Migrating Down Complete');
-
- return Promise.resolve(true);
-};
diff --git a/backend/lib/utils.js b/backend/lib/utils.js
deleted file mode 100644
index e2d60778..00000000
--- a/backend/lib/utils.js
+++ /dev/null
@@ -1,110 +0,0 @@
-const _ = require('lodash');
-const exec = require('node:child_process').exec;
-const execFile = require('node:child_process').execFile;
-const { Liquid } = require('liquidjs');
-const logger = require('../logger').global;
-const error = require('./error');
-
-module.exports = {
-
- exec: async (cmd, options = {}) => {
- logger.debug('CMD:', cmd);
-
- const { stdout, stderr } = await new Promise((resolve, reject) => {
- const child = exec(cmd, options, (isError, stdout, stderr) => {
- if (isError) {
- reject(new error.CommandError(stderr, isError));
- } else {
- resolve({ stdout, stderr });
- }
- });
-
- child.on('error', (e) => {
- reject(new error.CommandError(stderr, 1, e));
- });
- });
- return stdout;
- },
-
- /**
- * @param {String} cmd
- * @param {Array} args
- * @param {Object|undefined} options
- * @returns {Promise}
- */
- execFile: (cmd, args, options) => {
- logger.debug(`CMD: ${cmd} ${args ? args.join(' ') : ''}`);
- if (typeof options === 'undefined') {
- options = {};
- }
-
- return new Promise((resolve, reject) => {
- execFile(cmd, args, options, (err, stdout, stderr) => {
- if (err && typeof err === 'object') {
- reject(new error.CommandError(stderr, 1, err));
- } else {
- resolve(stdout.trim());
- }
- });
- });
- },
-
- /**
- * Used in objection query builder
- *
- * @param {Array} omissions
- * @returns {Function}
- */
- omitRow: (omissions) => {
- /**
- * @param {Object} row
- * @returns {Object}
- */
- return (row) => {
- return _.omit(row, omissions);
- };
- },
-
- /**
- * Used in objection query builder
- *
- * @param {Array} omissions
- * @returns {Function}
- */
- omitRows: (omissions) => {
- /**
- * @param {Array} rows
- * @returns {Object}
- */
- return (rows) => {
- rows.forEach((row, idx) => {
- rows[idx] = _.omit(row, omissions);
- });
- return rows;
- };
- },
-
- /**
- * @returns {Object} Liquid render engine
- */
- getRenderEngine: () => {
- const renderEngine = new Liquid({
- root: `${__dirname}/../templates/`
- });
-
- /**
- * nginxAccessRule expects the object given to have 2 properties:
- *
- * directive string
- * address string
- */
- renderEngine.registerFilter('nginxAccessRule', (v) => {
- if (typeof v.directive !== 'undefined' && typeof v.address !== 'undefined' && v.directive && v.address) {
- return `${v.directive} ${v.address};`;
- }
- return '';
- });
-
- return renderEngine;
- }
-};
diff --git a/backend/lib/validator/api.js b/backend/lib/validator/api.js
deleted file mode 100644
index fb31e64c..00000000
--- a/backend/lib/validator/api.js
+++ /dev/null
@@ -1,43 +0,0 @@
-const Ajv = require('ajv/dist/2020');
-const error = require('../error');
-
-const ajv = new Ajv({
- verbose: true,
- allErrors: true,
- allowUnionTypes: true,
- strict: false,
- coerceTypes: true,
-});
-
-/**
- * @param {Object} schema
- * @param {Object} payload
- * @returns {Promise}
- */
-function apiValidator (schema, payload/*, description*/) {
- return new Promise(function Promise_apiValidator (resolve, reject) {
- if (schema === null) {
- reject(new error.ValidationError('Schema is undefined'));
- return;
- }
-
- if (typeof payload === 'undefined') {
- reject(new error.ValidationError('Payload is undefined'));
- return;
- }
-
- const validate = ajv.compile(schema);
- const valid = validate(payload);
-
- if (valid && !validate.errors) {
- resolve(payload);
- } else {
- let message = ajv.errorsText(validate.errors);
- let err = new error.ValidationError(message);
- err.debug = [validate.errors, payload];
- reject(err);
- }
- });
-}
-
-module.exports = apiValidator;
diff --git a/backend/lib/validator/index.js b/backend/lib/validator/index.js
deleted file mode 100644
index c6d24096..00000000
--- a/backend/lib/validator/index.js
+++ /dev/null
@@ -1,45 +0,0 @@
-const _ = require('lodash');
-const Ajv = require('ajv/dist/2020');
-const error = require('../error');
-const commonDefinitions = require('../../schema/common.json');
-
-RegExp.prototype.toJSON = RegExp.prototype.toString;
-
-const ajv = new Ajv({
- verbose: true,
- allErrors: true,
- allowUnionTypes: true,
- coerceTypes: true,
- strict: false,
- schemas: [commonDefinitions]
-});
-
-/**
- *
- * @param {Object} schema
- * @param {Object} payload
- * @returns {Promise}
- */
-function validator (schema, payload) {
- return new Promise(function (resolve, reject) {
- if (!payload) {
- reject(new error.InternalValidationError('Payload is falsy'));
- } else {
- try {
- let validate = ajv.compile(schema);
- let valid = validate(payload);
-
- if (valid && !validate.errors) {
- resolve(_.cloneDeep(payload));
- } else {
- let message = ajv.errorsText(validate.errors);
- reject(new error.InternalValidationError(message));
- }
- } catch (err) {
- reject(err);
- }
- }
- });
-}
-
-module.exports = validator;
diff --git a/backend/logger.js b/backend/logger.js
deleted file mode 100644
index 0ebb07c5..00000000
--- a/backend/logger.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const {Signale} = require('signale');
-
-module.exports = {
- global: new Signale({scope: 'Global '}),
- migrate: new Signale({scope: 'Migrate '}),
- express: new Signale({scope: 'Express '}),
- access: new Signale({scope: 'Access '}),
- nginx: new Signale({scope: 'Nginx '}),
- ssl: new Signale({scope: 'SSL '}),
- certbot: new Signale({scope: 'Certbot '}),
- import: new Signale({scope: 'Importer '}),
- setup: new Signale({scope: 'Setup '}),
- ip_ranges: new Signale({scope: 'IP Ranges'})
-};
diff --git a/backend/migrate.js b/backend/migrate.js
deleted file mode 100644
index 263c8702..00000000
--- a/backend/migrate.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const db = require('./db');
-const logger = require('./logger').migrate;
-
-module.exports = {
- latest: function () {
- return db.migrate.currentVersion()
- .then((version) => {
- logger.info('Current database version:', version);
- return db.migrate.latest({
- tableName: 'migrations',
- directory: 'migrations'
- });
- });
- }
-};
diff --git a/backend/migrations/20180618015850_initial.js b/backend/migrations/20180618015850_initial.js
deleted file mode 100644
index a112e826..00000000
--- a/backend/migrations/20180618015850_initial.js
+++ /dev/null
@@ -1,205 +0,0 @@
-const migrate_name = 'initial-schema';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.createTable('auth', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('user_id').notNull().unsigned();
- table.string('type', 30).notNull();
- table.string('secret').notNull();
- table.json('meta').notNull();
- table.integer('is_deleted').notNull().unsigned().defaultTo(0);
- })
- .then(() => {
- logger.info('[' + migrate_name + '] auth Table created');
-
- return knex.schema.createTable('user', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('is_deleted').notNull().unsigned().defaultTo(0);
- table.integer('is_disabled').notNull().unsigned().defaultTo(0);
- table.string('email').notNull();
- table.string('name').notNull();
- table.string('nickname').notNull();
- table.string('avatar').notNull();
- table.json('roles').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] user Table created');
-
- return knex.schema.createTable('user_permission', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('user_id').notNull().unsigned();
- table.string('visibility').notNull();
- table.string('proxy_hosts').notNull();
- table.string('redirection_hosts').notNull();
- table.string('dead_hosts').notNull();
- table.string('streams').notNull();
- table.string('access_lists').notNull();
- table.string('certificates').notNull();
- table.unique('user_id');
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] user_permission Table created');
-
- return knex.schema.createTable('proxy_host', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('owner_user_id').notNull().unsigned();
- table.integer('is_deleted').notNull().unsigned().defaultTo(0);
- table.json('domain_names').notNull();
- table.string('forward_ip').notNull();
- table.integer('forward_port').notNull().unsigned();
- table.integer('access_list_id').notNull().unsigned().defaultTo(0);
- table.integer('certificate_id').notNull().unsigned().defaultTo(0);
- table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
- table.integer('caching_enabled').notNull().unsigned().defaultTo(0);
- table.integer('block_exploits').notNull().unsigned().defaultTo(0);
- table.text('advanced_config').notNull().defaultTo('');
- table.json('meta').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table created');
-
- return knex.schema.createTable('redirection_host', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('owner_user_id').notNull().unsigned();
- table.integer('is_deleted').notNull().unsigned().defaultTo(0);
- table.json('domain_names').notNull();
- table.string('forward_domain_name').notNull();
- table.integer('preserve_path').notNull().unsigned().defaultTo(0);
- table.integer('certificate_id').notNull().unsigned().defaultTo(0);
- table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
- table.integer('block_exploits').notNull().unsigned().defaultTo(0);
- table.text('advanced_config').notNull().defaultTo('');
- table.json('meta').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] redirection_host Table created');
-
- return knex.schema.createTable('dead_host', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('owner_user_id').notNull().unsigned();
- table.integer('is_deleted').notNull().unsigned().defaultTo(0);
- table.json('domain_names').notNull();
- table.integer('certificate_id').notNull().unsigned().defaultTo(0);
- table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
- table.text('advanced_config').notNull().defaultTo('');
- table.json('meta').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] dead_host Table created');
-
- return knex.schema.createTable('stream', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('owner_user_id').notNull().unsigned();
- table.integer('is_deleted').notNull().unsigned().defaultTo(0);
- table.integer('incoming_port').notNull().unsigned();
- table.string('forward_ip').notNull();
- table.integer('forwarding_port').notNull().unsigned();
- table.integer('tcp_forwarding').notNull().unsigned().defaultTo(0);
- table.integer('udp_forwarding').notNull().unsigned().defaultTo(0);
- table.json('meta').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] stream Table created');
-
- return knex.schema.createTable('access_list', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('owner_user_id').notNull().unsigned();
- table.integer('is_deleted').notNull().unsigned().defaultTo(0);
- table.string('name').notNull();
- table.json('meta').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] access_list Table created');
-
- return knex.schema.createTable('certificate', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('owner_user_id').notNull().unsigned();
- table.integer('is_deleted').notNull().unsigned().defaultTo(0);
- table.string('provider').notNull();
- table.string('nice_name').notNull().defaultTo('');
- table.json('domain_names').notNull();
- table.dateTime('expires_on').notNull();
- table.json('meta').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] certificate Table created');
-
- return knex.schema.createTable('access_list_auth', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('access_list_id').notNull().unsigned();
- table.string('username').notNull();
- table.string('password').notNull();
- table.json('meta').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] access_list_auth Table created');
-
- return knex.schema.createTable('audit_log', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('user_id').notNull().unsigned();
- table.string('object_type').notNull().defaultTo('');
- table.integer('object_id').notNull().unsigned().defaultTo(0);
- table.string('action').notNull();
- table.json('meta').notNull();
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] audit_log Table created');
- });
-
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down the initial data.');
- return Promise.resolve(true);
-};
diff --git a/backend/migrations/20180929054513_websockets.js b/backend/migrations/20180929054513_websockets.js
deleted file mode 100644
index 06054850..00000000
--- a/backend/migrations/20180929054513_websockets.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const migrate_name = 'websockets';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('proxy_host', function (proxy_host) {
- proxy_host.integer('allow_websocket_upgrade').notNull().unsigned().defaultTo(0);
- })
- .then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table altered');
- });
-
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
- return Promise.resolve(true);
-};
\ No newline at end of file
diff --git a/backend/migrations/20181019052346_forward_host.js b/backend/migrations/20181019052346_forward_host.js
deleted file mode 100644
index 05c27739..00000000
--- a/backend/migrations/20181019052346_forward_host.js
+++ /dev/null
@@ -1,34 +0,0 @@
-const migrate_name = 'forward_host';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('proxy_host', function (proxy_host) {
- proxy_host.renameColumn('forward_ip', 'forward_host');
- })
- .then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
- return Promise.resolve(true);
-};
\ No newline at end of file
diff --git a/backend/migrations/20181113041458_http2_support.js b/backend/migrations/20181113041458_http2_support.js
deleted file mode 100644
index 9f6b4336..00000000
--- a/backend/migrations/20181113041458_http2_support.js
+++ /dev/null
@@ -1,49 +0,0 @@
-const migrate_name = 'http2_support';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('proxy_host', function (proxy_host) {
- proxy_host.integer('http2_support').notNull().unsigned().defaultTo(0);
- })
- .then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table altered');
-
- return knex.schema.table('redirection_host', function (redirection_host) {
- redirection_host.integer('http2_support').notNull().unsigned().defaultTo(0);
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] redirection_host Table altered');
-
- return knex.schema.table('dead_host', function (dead_host) {
- dead_host.integer('http2_support').notNull().unsigned().defaultTo(0);
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] dead_host Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
- return Promise.resolve(true);
-};
-
diff --git a/backend/migrations/20181213013211_forward_scheme.js b/backend/migrations/20181213013211_forward_scheme.js
deleted file mode 100644
index 22ae619e..00000000
--- a/backend/migrations/20181213013211_forward_scheme.js
+++ /dev/null
@@ -1,34 +0,0 @@
-const migrate_name = 'forward_scheme';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('proxy_host', function (proxy_host) {
- proxy_host.string('forward_scheme').notNull().defaultTo('http');
- })
- .then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
- return Promise.resolve(true);
-};
diff --git a/backend/migrations/20190104035154_disabled.js b/backend/migrations/20190104035154_disabled.js
deleted file mode 100644
index 2780c4df..00000000
--- a/backend/migrations/20190104035154_disabled.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const migrate_name = 'disabled';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('proxy_host', function (proxy_host) {
- proxy_host.integer('enabled').notNull().unsigned().defaultTo(1);
- })
- .then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table altered');
-
- return knex.schema.table('redirection_host', function (redirection_host) {
- redirection_host.integer('enabled').notNull().unsigned().defaultTo(1);
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] redirection_host Table altered');
-
- return knex.schema.table('dead_host', function (dead_host) {
- dead_host.integer('enabled').notNull().unsigned().defaultTo(1);
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] dead_host Table altered');
-
- return knex.schema.table('stream', function (stream) {
- stream.integer('enabled').notNull().unsigned().defaultTo(1);
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] stream Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
- return Promise.resolve(true);
-};
diff --git a/backend/migrations/20190215115310_customlocations.js b/backend/migrations/20190215115310_customlocations.js
deleted file mode 100644
index 4bcfd51a..00000000
--- a/backend/migrations/20190215115310_customlocations.js
+++ /dev/null
@@ -1,35 +0,0 @@
-const migrate_name = 'custom_locations';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- * Extends proxy_host table with locations field
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('proxy_host', function (proxy_host) {
- proxy_host.json('locations');
- })
- .then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
- return Promise.resolve(true);
-};
diff --git a/backend/migrations/20190218060101_hsts.js b/backend/migrations/20190218060101_hsts.js
deleted file mode 100644
index 648b162a..00000000
--- a/backend/migrations/20190218060101_hsts.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const migrate_name = 'hsts';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('proxy_host', function (proxy_host) {
- proxy_host.integer('hsts_enabled').notNull().unsigned().defaultTo(0);
- proxy_host.integer('hsts_subdomains').notNull().unsigned().defaultTo(0);
- })
- .then(() => {
- logger.info('[' + migrate_name + '] proxy_host Table altered');
-
- return knex.schema.table('redirection_host', function (redirection_host) {
- redirection_host.integer('hsts_enabled').notNull().unsigned().defaultTo(0);
- redirection_host.integer('hsts_subdomains').notNull().unsigned().defaultTo(0);
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] redirection_host Table altered');
-
- return knex.schema.table('dead_host', function (dead_host) {
- dead_host.integer('hsts_enabled').notNull().unsigned().defaultTo(0);
- dead_host.integer('hsts_subdomains').notNull().unsigned().defaultTo(0);
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] dead_host Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
- return Promise.resolve(true);
-};
diff --git a/backend/migrations/20190227065017_settings.js b/backend/migrations/20190227065017_settings.js
deleted file mode 100644
index 7dc9c192..00000000
--- a/backend/migrations/20190227065017_settings.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const migrate_name = 'settings';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.createTable('setting', (table) => {
- table.string('id').notNull().primary();
- table.string('name', 100).notNull();
- table.string('description', 255).notNull();
- table.string('value', 255).notNull();
- table.json('meta').notNull();
- })
- .then(() => {
- logger.info('[' + migrate_name + '] setting Table created');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down the initial data.');
- return Promise.resolve(true);
-};
diff --git a/backend/migrations/20200410143839_access_list_client.js b/backend/migrations/20200410143839_access_list_client.js
deleted file mode 100644
index 3511e35b..00000000
--- a/backend/migrations/20200410143839_access_list_client.js
+++ /dev/null
@@ -1,53 +0,0 @@
-const migrate_name = 'access_list_client';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
-
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.createTable('access_list_client', (table) => {
- table.increments().primary();
- table.dateTime('created_on').notNull();
- table.dateTime('modified_on').notNull();
- table.integer('access_list_id').notNull().unsigned();
- table.string('address').notNull();
- table.string('directive').notNull();
- table.json('meta').notNull();
-
- })
- .then(function () {
- logger.info('[' + migrate_name + '] access_list_client Table created');
-
- return knex.schema.table('access_list', function (access_list) {
- access_list.integer('satify_any').notNull().defaultTo(0);
- });
- })
- .then(() => {
- logger.info('[' + migrate_name + '] access_list Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Down...');
-
- return knex.schema.dropTable('access_list_client')
- .then(() => {
- logger.info('[' + migrate_name + '] access_list_client Table dropped');
- });
-};
diff --git a/backend/migrations/20200410143840_access_list_client_fix.js b/backend/migrations/20200410143840_access_list_client_fix.js
deleted file mode 100644
index ee0f0906..00000000
--- a/backend/migrations/20200410143840_access_list_client_fix.js
+++ /dev/null
@@ -1,34 +0,0 @@
-const migrate_name = 'access_list_client_fix';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('access_list', function (access_list) {
- access_list.renameColumn('satify_any', 'satisfy_any');
- })
- .then(() => {
- logger.info('[' + migrate_name + '] access_list Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex, Promise) {
- logger.warn('[' + migrate_name + '] You can\'t migrate down this one.');
- return Promise.resolve(true);
-};
diff --git a/backend/migrations/20201014143841_pass_auth.js b/backend/migrations/20201014143841_pass_auth.js
deleted file mode 100644
index a7767eb1..00000000
--- a/backend/migrations/20201014143841_pass_auth.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const migrate_name = 'pass_auth';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
-
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('access_list', function (access_list) {
- access_list.integer('pass_auth').notNull().defaultTo(1);
- })
- .then(() => {
- logger.info('[' + migrate_name + '] access_list Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Down...');
-
- return knex.schema.table('access_list', function (access_list) {
- access_list.dropColumn('pass_auth');
- })
- .then(() => {
- logger.info('[' + migrate_name + '] access_list pass_auth Column dropped');
- });
-};
diff --git a/backend/migrations/20210210154702_redirection_scheme.js b/backend/migrations/20210210154702_redirection_scheme.js
deleted file mode 100644
index 0dad4876..00000000
--- a/backend/migrations/20210210154702_redirection_scheme.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const migrate_name = 'redirection_scheme';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
-
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('redirection_host', (table) => {
- table.string('forward_scheme').notNull().defaultTo('$scheme');
- })
- .then(function () {
- logger.info('[' + migrate_name + '] redirection_host Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Down...');
-
- return knex.schema.table('redirection_host', (table) => {
- table.dropColumn('forward_scheme');
- })
- .then(function () {
- logger.info('[' + migrate_name + '] redirection_host Table altered');
- });
-};
diff --git a/backend/migrations/20210210154703_redirection_status_code.js b/backend/migrations/20210210154703_redirection_status_code.js
deleted file mode 100644
index b9bea0b9..00000000
--- a/backend/migrations/20210210154703_redirection_status_code.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const migrate_name = 'redirection_status_code';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
-
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('redirection_host', (table) => {
- table.integer('forward_http_code').notNull().unsigned().defaultTo(302);
- })
- .then(function () {
- logger.info('[' + migrate_name + '] redirection_host Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Down...');
-
- return knex.schema.table('redirection_host', (table) => {
- table.dropColumn('forward_http_code');
- })
- .then(function () {
- logger.info('[' + migrate_name + '] redirection_host Table altered');
- });
-};
diff --git a/backend/migrations/20210423103500_stream_domain.js b/backend/migrations/20210423103500_stream_domain.js
deleted file mode 100644
index a894ca5e..00000000
--- a/backend/migrations/20210423103500_stream_domain.js
+++ /dev/null
@@ -1,40 +0,0 @@
-const migrate_name = 'stream_domain';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('stream', (table) => {
- table.renameColumn('forward_ip', 'forwarding_host');
- })
- .then(function () {
- logger.info('[' + migrate_name + '] stream Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex/*, Promise*/) {
- logger.info('[' + migrate_name + '] Migrating Down...');
-
- return knex.schema.table('stream', (table) => {
- table.renameColumn('forwarding_host', 'forward_ip');
- })
- .then(function () {
- logger.info('[' + migrate_name + '] stream Table altered');
- });
-};
diff --git a/backend/migrations/20211108145214_regenerate_default_host.js b/backend/migrations/20211108145214_regenerate_default_host.js
deleted file mode 100644
index 4c50941f..00000000
--- a/backend/migrations/20211108145214_regenerate_default_host.js
+++ /dev/null
@@ -1,50 +0,0 @@
-const migrate_name = 'stream_domain';
-const logger = require('../logger').migrate;
-const internalNginx = require('../internal/nginx');
-
-async function regenerateDefaultHost(knex) {
- const row = await knex('setting').select('*').where('id', 'default-site').first();
-
- if (!row) {
- return Promise.resolve();
- }
-
- return internalNginx.deleteConfig('default')
- .then(() => {
- return internalNginx.generateConfig('default', row);
- })
- .then(() => {
- return internalNginx.test();
- })
- .then(() => {
- return internalNginx.reload();
- });
-}
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.up = function (knex) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return regenerateDefaultHost(knex);
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @param {Promise} Promise
- * @returns {Promise}
- */
-exports.down = function (knex) {
- logger.info('[' + migrate_name + '] Migrating Down...');
-
- return regenerateDefaultHost(knex);
-};
\ No newline at end of file
diff --git a/backend/migrations/20240427161436_stream_ssl.js b/backend/migrations/20240427161436_stream_ssl.js
deleted file mode 100644
index 5f47b18e..00000000
--- a/backend/migrations/20240427161436_stream_ssl.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const migrate_name = 'stream_ssl';
-const logger = require('../logger').migrate;
-
-/**
- * Migrate
- *
- * @see http://knexjs.org/#Schema
- *
- * @param {Object} knex
- * @returns {Promise}
- */
-exports.up = function (knex) {
- logger.info('[' + migrate_name + '] Migrating Up...');
-
- return knex.schema.table('stream', (table) => {
- table.integer('certificate_id').notNull().unsigned().defaultTo(0);
- })
- .then(function () {
- logger.info('[' + migrate_name + '] stream Table altered');
- });
-};
-
-/**
- * Undo Migrate
- *
- * @param {Object} knex
- * @returns {Promise}
- */
-exports.down = function (knex) {
- logger.info('[' + migrate_name + '] Migrating Down...');
-
- return knex.schema.table('stream', (table) => {
- table.dropColumn('certificate_id');
- })
- .then(function () {
- logger.info('[' + migrate_name + '] stream Table altered');
- });
-};
diff --git a/backend/models/access_list.js b/backend/models/access_list.js
deleted file mode 100644
index 959df05f..00000000
--- a/backend/models/access_list.js
+++ /dev/null
@@ -1,103 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const helpers = require('../lib/helpers');
-const Model = require('objection').Model;
-const User = require('./user');
-const AccessListAuth = require('./access_list_auth');
-const AccessListClient = require('./access_list_client');
-const now = require('./now_helper');
-
-Model.knex(db);
-
-const boolFields = [
- 'is_deleted',
- 'satisfy_any',
- 'pass_auth',
-];
-
-class AccessList extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
- }
-
- $beforeUpdate () {
- this.modified_on = now();
- }
-
- $parseDatabaseJson(json) {
- json = super.$parseDatabaseJson(json);
- return helpers.convertIntFieldsToBool(json, boolFields);
- }
-
- $formatDatabaseJson(json) {
- json = helpers.convertBoolFieldsToInt(json, boolFields);
- return super.$formatDatabaseJson(json);
- }
-
- static get name () {
- return 'AccessList';
- }
-
- static get tableName () {
- return 'access_list';
- }
-
- static get jsonAttributes () {
- return ['meta'];
- }
-
- static get relationMappings () {
- const ProxyHost = require('./proxy_host');
-
- return {
- owner: {
- relation: Model.HasOneRelation,
- modelClass: User,
- join: {
- from: 'access_list.owner_user_id',
- to: 'user.id'
- },
- modify: function (qb) {
- qb.where('user.is_deleted', 0);
- }
- },
- items: {
- relation: Model.HasManyRelation,
- modelClass: AccessListAuth,
- join: {
- from: 'access_list.id',
- to: 'access_list_auth.access_list_id'
- }
- },
- clients: {
- relation: Model.HasManyRelation,
- modelClass: AccessListClient,
- join: {
- from: 'access_list.id',
- to: 'access_list_client.access_list_id'
- }
- },
- proxy_hosts: {
- relation: Model.HasManyRelation,
- modelClass: ProxyHost,
- join: {
- from: 'access_list.id',
- to: 'proxy_host.access_list_id'
- },
- modify: function (qb) {
- qb.where('proxy_host.is_deleted', 0);
- }
- }
- };
- }
-}
-
-module.exports = AccessList;
diff --git a/backend/models/access_list_auth.js b/backend/models/access_list_auth.js
deleted file mode 100644
index 3895539c..00000000
--- a/backend/models/access_list_auth.js
+++ /dev/null
@@ -1,54 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const Model = require('objection').Model;
-const now = require('./now_helper');
-
-Model.knex(db);
-
-class AccessListAuth extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
- }
-
- $beforeUpdate () {
- this.modified_on = now();
- }
-
- static get name () {
- return 'AccessListAuth';
- }
-
- static get tableName () {
- return 'access_list_auth';
- }
-
- static get jsonAttributes () {
- return ['meta'];
- }
-
- static get relationMappings () {
- return {
- access_list: {
- relation: Model.HasOneRelation,
- modelClass: require('./access_list'),
- join: {
- from: 'access_list_auth.access_list_id',
- to: 'access_list.id'
- },
- modify: function (qb) {
- qb.where('access_list.is_deleted', 0);
- }
- }
- };
- }
-}
-
-module.exports = AccessListAuth;
diff --git a/backend/models/access_list_client.js b/backend/models/access_list_client.js
deleted file mode 100644
index bffc0023..00000000
--- a/backend/models/access_list_client.js
+++ /dev/null
@@ -1,54 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const Model = require('objection').Model;
-const now = require('./now_helper');
-
-Model.knex(db);
-
-class AccessListClient extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
- }
-
- $beforeUpdate () {
- this.modified_on = now();
- }
-
- static get name () {
- return 'AccessListClient';
- }
-
- static get tableName () {
- return 'access_list_client';
- }
-
- static get jsonAttributes () {
- return ['meta'];
- }
-
- static get relationMappings () {
- return {
- access_list: {
- relation: Model.HasOneRelation,
- modelClass: require('./access_list'),
- join: {
- from: 'access_list_client.access_list_id',
- to: 'access_list.id'
- },
- modify: function (qb) {
- qb.where('access_list.is_deleted', 0);
- }
- }
- };
- }
-}
-
-module.exports = AccessListClient;
diff --git a/backend/models/audit-log.js b/backend/models/audit-log.js
deleted file mode 100644
index 45a4b460..00000000
--- a/backend/models/audit-log.js
+++ /dev/null
@@ -1,52 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const Model = require('objection').Model;
-const User = require('./user');
-const now = require('./now_helper');
-
-Model.knex(db);
-
-class AuditLog extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
- }
-
- $beforeUpdate () {
- this.modified_on = now();
- }
-
- static get name () {
- return 'AuditLog';
- }
-
- static get tableName () {
- return 'audit_log';
- }
-
- static get jsonAttributes () {
- return ['meta'];
- }
-
- static get relationMappings () {
- return {
- user: {
- relation: Model.HasOneRelation,
- modelClass: User,
- join: {
- from: 'audit_log.user_id',
- to: 'user.id'
- }
- }
- };
- }
-}
-
-module.exports = AuditLog;
diff --git a/backend/models/auth.js b/backend/models/auth.js
deleted file mode 100644
index 469e96bf..00000000
--- a/backend/models/auth.js
+++ /dev/null
@@ -1,98 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const bcrypt = require('bcrypt');
-const db = require('../db');
-const helpers = require('../lib/helpers');
-const Model = require('objection').Model;
-const User = require('./user');
-const now = require('./now_helper');
-
-Model.knex(db);
-
-const boolFields = [
- 'is_deleted',
-];
-
-function encryptPassword () {
- /* jshint -W040 */
- let _this = this;
-
- if (_this.type === 'password' && _this.secret) {
- return bcrypt.hash(_this.secret, 13)
- .then(function (hash) {
- _this.secret = hash;
- });
- }
-
- return null;
-}
-
-class Auth extends Model {
- $beforeInsert (queryContext) {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
-
- return encryptPassword.apply(this, queryContext);
- }
-
- $beforeUpdate (queryContext) {
- this.modified_on = now();
- return encryptPassword.apply(this, queryContext);
- }
-
- $parseDatabaseJson(json) {
- json = super.$parseDatabaseJson(json);
- return helpers.convertIntFieldsToBool(json, boolFields);
- }
-
- $formatDatabaseJson(json) {
- json = helpers.convertBoolFieldsToInt(json, boolFields);
- return super.$formatDatabaseJson(json);
- }
-
- /**
- * Verify a plain password against the encrypted password
- *
- * @param {String} password
- * @returns {Promise}
- */
- verifyPassword (password) {
- return bcrypt.compare(password, this.secret);
- }
-
- static get name () {
- return 'Auth';
- }
-
- static get tableName () {
- return 'auth';
- }
-
- static get jsonAttributes () {
- return ['meta'];
- }
-
- static get relationMappings () {
- return {
- user: {
- relation: Model.HasOneRelation,
- modelClass: User,
- join: {
- from: 'auth.user_id',
- to: 'user.id'
- },
- filter: {
- is_deleted: 0
- }
- }
- };
- }
-}
-
-module.exports = Auth;
diff --git a/backend/models/certificate.js b/backend/models/certificate.js
deleted file mode 100644
index d4ea21ad..00000000
--- a/backend/models/certificate.js
+++ /dev/null
@@ -1,124 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const helpers = require('../lib/helpers');
-const Model = require('objection').Model;
-const now = require('./now_helper');
-
-Model.knex(db);
-
-const boolFields = [
- 'is_deleted',
-];
-
-class Certificate extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for expires_on
- if (typeof this.expires_on === 'undefined') {
- this.expires_on = now();
- }
-
- // Default for domain_names
- if (typeof this.domain_names === 'undefined') {
- this.domain_names = [];
- }
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
-
- this.domain_names.sort();
- }
-
- $beforeUpdate () {
- this.modified_on = now();
-
- // Sort domain_names
- if (typeof this.domain_names !== 'undefined') {
- this.domain_names.sort();
- }
- }
-
- $parseDatabaseJson(json) {
- json = super.$parseDatabaseJson(json);
- return helpers.convertIntFieldsToBool(json, boolFields);
- }
-
- $formatDatabaseJson(json) {
- json = helpers.convertBoolFieldsToInt(json, boolFields);
- return super.$formatDatabaseJson(json);
- }
-
- static get name () {
- return 'Certificate';
- }
-
- static get tableName () {
- return 'certificate';
- }
-
- static get jsonAttributes () {
- return ['domain_names', 'meta'];
- }
-
- static get relationMappings () {
- const ProxyHost = require('./proxy_host');
- const DeadHost = require('./dead_host');
- const User = require('./user');
- const RedirectionHost = require('./redirection_host');
-
- return {
- owner: {
- relation: Model.HasOneRelation,
- modelClass: User,
- join: {
- from: 'certificate.owner_user_id',
- to: 'user.id'
- },
- modify: function (qb) {
- qb.where('user.is_deleted', 0);
- }
- },
- proxy_hosts: {
- relation: Model.HasManyRelation,
- modelClass: ProxyHost,
- join: {
- from: 'certificate.id',
- to: 'proxy_host.certificate_id'
- },
- modify: function (qb) {
- qb.where('proxy_host.is_deleted', 0);
- }
- },
- dead_hosts: {
- relation: Model.HasManyRelation,
- modelClass: DeadHost,
- join: {
- from: 'certificate.id',
- to: 'dead_host.certificate_id'
- },
- modify: function (qb) {
- qb.where('dead_host.is_deleted', 0);
- }
- },
- redirection_hosts: {
- relation: Model.HasManyRelation,
- modelClass: RedirectionHost,
- join: {
- from: 'certificate.id',
- to: 'redirection_host.certificate_id'
- },
- modify: function (qb) {
- qb.where('redirection_host.is_deleted', 0);
- }
- }
- };
- }
-}
-
-module.exports = Certificate;
diff --git a/backend/models/dead_host.js b/backend/models/dead_host.js
deleted file mode 100644
index 3386caab..00000000
--- a/backend/models/dead_host.js
+++ /dev/null
@@ -1,99 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const helpers = require('../lib/helpers');
-const Model = require('objection').Model;
-const User = require('./user');
-const Certificate = require('./certificate');
-const now = require('./now_helper');
-
-Model.knex(db);
-
-const boolFields = [
- 'is_deleted',
- 'ssl_forced',
- 'http2_support',
- 'enabled',
- 'hsts_enabled',
- 'hsts_subdomains',
-];
-
-class DeadHost extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for domain_names
- if (typeof this.domain_names === 'undefined') {
- this.domain_names = [];
- }
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
-
- this.domain_names.sort();
- }
-
- $beforeUpdate () {
- this.modified_on = now();
-
- // Sort domain_names
- if (typeof this.domain_names !== 'undefined') {
- this.domain_names.sort();
- }
- }
-
- $parseDatabaseJson(json) {
- json = super.$parseDatabaseJson(json);
- return helpers.convertIntFieldsToBool(json, boolFields);
- }
-
- $formatDatabaseJson(json) {
- json = helpers.convertBoolFieldsToInt(json, boolFields);
- return super.$formatDatabaseJson(json);
- }
-
- static get name () {
- return 'DeadHost';
- }
-
- static get tableName () {
- return 'dead_host';
- }
-
- static get jsonAttributes () {
- return ['domain_names', 'meta'];
- }
-
- static get relationMappings () {
- return {
- owner: {
- relation: Model.HasOneRelation,
- modelClass: User,
- join: {
- from: 'dead_host.owner_user_id',
- to: 'user.id'
- },
- modify: function (qb) {
- qb.where('user.is_deleted', 0);
- }
- },
- certificate: {
- relation: Model.HasOneRelation,
- modelClass: Certificate,
- join: {
- from: 'dead_host.certificate_id',
- to: 'certificate.id'
- },
- modify: function (qb) {
- qb.where('certificate.is_deleted', 0);
- }
- }
- };
- }
-}
-
-module.exports = DeadHost;
diff --git a/backend/models/now_helper.js b/backend/models/now_helper.js
deleted file mode 100644
index dec70c3d..00000000
--- a/backend/models/now_helper.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const db = require('../db');
-const config = require('../lib/config');
-const Model = require('objection').Model;
-
-Model.knex(db);
-
-module.exports = function () {
- if (config.isSqlite()) {
- // eslint-disable-next-line
- return Model.raw("datetime('now','localtime')");
- }
- return Model.raw('NOW()');
-};
diff --git a/backend/models/proxy_host.js b/backend/models/proxy_host.js
deleted file mode 100644
index 07aa5dd3..00000000
--- a/backend/models/proxy_host.js
+++ /dev/null
@@ -1,114 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const helpers = require('../lib/helpers');
-const Model = require('objection').Model;
-const User = require('./user');
-const AccessList = require('./access_list');
-const Certificate = require('./certificate');
-const now = require('./now_helper');
-
-Model.knex(db);
-
-const boolFields = [
- 'is_deleted',
- 'ssl_forced',
- 'caching_enabled',
- 'block_exploits',
- 'allow_websocket_upgrade',
- 'http2_support',
- 'enabled',
- 'hsts_enabled',
- 'hsts_subdomains',
-];
-
-class ProxyHost extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for domain_names
- if (typeof this.domain_names === 'undefined') {
- this.domain_names = [];
- }
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
-
- this.domain_names.sort();
- }
-
- $beforeUpdate () {
- this.modified_on = now();
-
- // Sort domain_names
- if (typeof this.domain_names !== 'undefined') {
- this.domain_names.sort();
- }
- }
-
- $parseDatabaseJson(json) {
- json = super.$parseDatabaseJson(json);
- return helpers.convertIntFieldsToBool(json, boolFields);
- }
-
- $formatDatabaseJson(json) {
- json = helpers.convertBoolFieldsToInt(json, boolFields);
- return super.$formatDatabaseJson(json);
- }
-
- static get name () {
- return 'ProxyHost';
- }
-
- static get tableName () {
- return 'proxy_host';
- }
-
- static get jsonAttributes () {
- return ['domain_names', 'meta', 'locations'];
- }
-
- static get relationMappings () {
- return {
- owner: {
- relation: Model.HasOneRelation,
- modelClass: User,
- join: {
- from: 'proxy_host.owner_user_id',
- to: 'user.id'
- },
- modify: function (qb) {
- qb.where('user.is_deleted', 0);
- }
- },
- access_list: {
- relation: Model.HasOneRelation,
- modelClass: AccessList,
- join: {
- from: 'proxy_host.access_list_id',
- to: 'access_list.id'
- },
- modify: function (qb) {
- qb.where('access_list.is_deleted', 0);
- }
- },
- certificate: {
- relation: Model.HasOneRelation,
- modelClass: Certificate,
- join: {
- from: 'proxy_host.certificate_id',
- to: 'certificate.id'
- },
- modify: function (qb) {
- qb.where('certificate.is_deleted', 0);
- }
- }
- };
- }
-}
-
-module.exports = ProxyHost;
diff --git a/backend/models/redirection_host.js b/backend/models/redirection_host.js
deleted file mode 100644
index 80162791..00000000
--- a/backend/models/redirection_host.js
+++ /dev/null
@@ -1,102 +0,0 @@
-
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const helpers = require('../lib/helpers');
-const Model = require('objection').Model;
-const User = require('./user');
-const Certificate = require('./certificate');
-const now = require('./now_helper');
-
-Model.knex(db);
-
-const boolFields = [
- 'is_deleted',
- 'enabled',
- 'preserve_path',
- 'ssl_forced',
- 'block_exploits',
- 'hsts_enabled',
- 'hsts_subdomains',
- 'http2_support',
-];
-
-class RedirectionHost extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for domain_names
- if (typeof this.domain_names === 'undefined') {
- this.domain_names = [];
- }
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
-
- this.domain_names.sort();
- }
-
- $beforeUpdate () {
- this.modified_on = now();
-
- // Sort domain_names
- if (typeof this.domain_names !== 'undefined') {
- this.domain_names.sort();
- }
- }
-
- $parseDatabaseJson(json) {
- json = super.$parseDatabaseJson(json);
- return helpers.convertIntFieldsToBool(json, boolFields);
- }
-
- $formatDatabaseJson(json) {
- json = helpers.convertBoolFieldsToInt(json, boolFields);
- return super.$formatDatabaseJson(json);
- }
-
- static get name () {
- return 'RedirectionHost';
- }
-
- static get tableName () {
- return 'redirection_host';
- }
-
- static get jsonAttributes () {
- return ['domain_names', 'meta'];
- }
-
- static get relationMappings () {
- return {
- owner: {
- relation: Model.HasOneRelation,
- modelClass: User,
- join: {
- from: 'redirection_host.owner_user_id',
- to: 'user.id'
- },
- modify: function (qb) {
- qb.where('user.is_deleted', 0);
- }
- },
- certificate: {
- relation: Model.HasOneRelation,
- modelClass: Certificate,
- join: {
- from: 'redirection_host.certificate_id',
- to: 'certificate.id'
- },
- modify: function (qb) {
- qb.where('certificate.is_deleted', 0);
- }
- }
- };
- }
-}
-
-module.exports = RedirectionHost;
diff --git a/backend/models/setting.js b/backend/models/setting.js
deleted file mode 100644
index 75aa9007..00000000
--- a/backend/models/setting.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const Model = require('objection').Model;
-
-Model.knex(db);
-
-class Setting extends Model {
- $beforeInsert () {
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
- }
-
- static get name () {
- return 'Setting';
- }
-
- static get tableName () {
- return 'setting';
- }
-
- static get jsonAttributes () {
- return ['meta'];
- }
-}
-
-module.exports = Setting;
diff --git a/backend/models/stream.js b/backend/models/stream.js
deleted file mode 100644
index 5d1cb6c1..00000000
--- a/backend/models/stream.js
+++ /dev/null
@@ -1,82 +0,0 @@
-const Model = require('objection').Model;
-const db = require('../db');
-const helpers = require('../lib/helpers');
-const User = require('./user');
-const Certificate = require('./certificate');
-const now = require('./now_helper');
-
-Model.knex(db);
-
-const boolFields = [
- 'is_deleted',
- 'enabled',
- 'tcp_forwarding',
- 'udp_forwarding',
-];
-
-class Stream extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for meta
- if (typeof this.meta === 'undefined') {
- this.meta = {};
- }
- }
-
- $beforeUpdate () {
- this.modified_on = now();
- }
-
- $parseDatabaseJson(json) {
- json = super.$parseDatabaseJson(json);
- return helpers.convertIntFieldsToBool(json, boolFields);
- }
-
- $formatDatabaseJson(json) {
- json = helpers.convertBoolFieldsToInt(json, boolFields);
- return super.$formatDatabaseJson(json);
- }
-
- static get name () {
- return 'Stream';
- }
-
- static get tableName () {
- return 'stream';
- }
-
- static get jsonAttributes () {
- return ['meta'];
- }
-
- static get relationMappings () {
- return {
- owner: {
- relation: Model.HasOneRelation,
- modelClass: User,
- join: {
- from: 'stream.owner_user_id',
- to: 'user.id'
- },
- modify: function (qb) {
- qb.where('user.is_deleted', 0);
- }
- },
- certificate: {
- relation: Model.HasOneRelation,
- modelClass: Certificate,
- join: {
- from: 'stream.certificate_id',
- to: 'certificate.id'
- },
- modify: function (qb) {
- qb.where('certificate.is_deleted', 0);
- }
- }
- };
- }
-}
-
-module.exports = Stream;
diff --git a/backend/models/token.js b/backend/models/token.js
deleted file mode 100644
index 7cf11e03..00000000
--- a/backend/models/token.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- NOTE: This is not a database table, this is a model of a Token object that can be created/loaded
- and then has abilities after that.
- */
-
-const _ = require('lodash');
-const jwt = require('jsonwebtoken');
-const crypto = require('crypto');
-const config = require('../lib/config');
-const error = require('../lib/error');
-const logger = require('../logger').global;
-const ALGO = 'RS256';
-
-module.exports = function () {
-
- let token_data = {};
-
- const self = {
- /**
- * @param {Object} payload
- * @returns {Promise}
- */
- create: (payload) => {
- if (!config.getPrivateKey()) {
- logger.error('Private key is empty!');
- }
- // sign with RSA SHA256
- const options = {
- algorithm: ALGO,
- expiresIn: payload.expiresIn || '1d'
- };
-
- payload.jti = crypto.randomBytes(12)
- .toString('base64')
- .substring(-8);
-
- return new Promise((resolve, reject) => {
- jwt.sign(payload, config.getPrivateKey(), options, (err, token) => {
- if (err) {
- reject(err);
- } else {
- token_data = payload;
- resolve({
- token: token,
- payload: payload
- });
- }
- });
- });
- },
-
- /**
- * @param {String} token
- * @returns {Promise}
- */
- load: function (token) {
- if (!config.getPublicKey()) {
- logger.error('Public key is empty!');
- }
- return new Promise((resolve, reject) => {
- try {
- if (!token || token === null || token === 'null') {
- reject(new error.AuthError('Empty token'));
- } else {
- jwt.verify(token, config.getPublicKey(), {ignoreExpiration: false, algorithms: [ALGO]}, (err, result) => {
- if (err) {
-
- if (err.name === 'TokenExpiredError') {
- reject(new error.AuthError('Token has expired', err));
- } else {
- reject(err);
- }
-
- } else {
- token_data = result;
-
- // Hack: some tokens out in the wild have a scope of 'all' instead of 'user'.
- // For 30 days at least, we need to replace 'all' with user.
- if ((typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, 'all') !== -1)) {
- token_data.scope = ['user'];
- }
-
- resolve(token_data);
- }
- });
- }
- } catch (err) {
- reject(err);
- }
- });
-
- },
-
- /**
- * Does the token have the specified scope?
- *
- * @param {String} scope
- * @returns {Boolean}
- */
- hasScope: function (scope) {
- return typeof token_data.scope !== 'undefined' && _.indexOf(token_data.scope, scope) !== -1;
- },
-
- /**
- * @param {String} key
- * @return {*}
- */
- get: function (key) {
- if (typeof token_data[key] !== 'undefined') {
- return token_data[key];
- }
-
- return null;
- },
-
- /**
- * @param {String} key
- * @param {*} value
- */
- set: function (key, value) {
- token_data[key] = value;
- },
-
- /**
- * @param [default_value]
- * @returns {Integer}
- */
- getUserId: (default_value) => {
- const attrs = self.get('attrs');
- if (attrs && typeof attrs.id !== 'undefined' && attrs.id) {
- return attrs.id;
- }
-
- return default_value || 0;
- }
- };
-
- return self;
-};
diff --git a/backend/models/user.js b/backend/models/user.js
deleted file mode 100644
index 78fd3dd6..00000000
--- a/backend/models/user.js
+++ /dev/null
@@ -1,69 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const helpers = require('../lib/helpers');
-const Model = require('objection').Model;
-const UserPermission = require('./user_permission');
-const now = require('./now_helper');
-
-Model.knex(db);
-
-const boolFields = [
- 'is_deleted',
- 'is_disabled',
-];
-
-class User extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
-
- // Default for roles
- if (typeof this.roles === 'undefined') {
- this.roles = [];
- }
- }
-
- $beforeUpdate () {
- this.modified_on = now();
- }
-
- $parseDatabaseJson(json) {
- json = super.$parseDatabaseJson(json);
- return helpers.convertIntFieldsToBool(json, boolFields);
- }
-
- $formatDatabaseJson(json) {
- json = helpers.convertBoolFieldsToInt(json, boolFields);
- return super.$formatDatabaseJson(json);
- }
-
- static get name () {
- return 'User';
- }
-
- static get tableName () {
- return 'user';
- }
-
- static get jsonAttributes () {
- return ['roles'];
- }
-
- static get relationMappings () {
- return {
- permissions: {
- relation: Model.HasOneRelation,
- modelClass: UserPermission,
- join: {
- from: 'user.id',
- to: 'user_permission.user_id'
- }
- }
- };
- }
-
-}
-
-module.exports = User;
diff --git a/backend/models/user_permission.js b/backend/models/user_permission.js
deleted file mode 100644
index bb87d5dc..00000000
--- a/backend/models/user_permission.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Objection Docs:
-// http://vincit.github.io/objection.js/
-
-const db = require('../db');
-const Model = require('objection').Model;
-const now = require('./now_helper');
-
-Model.knex(db);
-
-class UserPermission extends Model {
- $beforeInsert () {
- this.created_on = now();
- this.modified_on = now();
- }
-
- $beforeUpdate () {
- this.modified_on = now();
- }
-
- static get name () {
- return 'UserPermission';
- }
-
- static get tableName () {
- return 'user_permission';
- }
-}
-
-module.exports = UserPermission;
diff --git a/backend/nodemon.json b/backend/nodemon.json
deleted file mode 100644
index 3d6d1342..00000000
--- a/backend/nodemon.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "verbose": false,
- "ignore": [
- "data"
- ],
- "ext": "js json ejs"
-}
diff --git a/backend/package.json b/backend/package.json
deleted file mode 100644
index 30984a33..00000000
--- a/backend/package.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "name": "nginx-proxy-manager",
- "version": "0.0.0",
- "description": "A beautiful interface for creating Nginx endpoints",
- "main": "index.js",
- "dependencies": {
- "@apidevtools/json-schema-ref-parser": "^11.7.0",
- "ajv": "^8.17.1",
- "archiver": "^5.3.0",
- "batchflow": "^0.4.0",
- "bcrypt": "^5.0.0",
- "body-parser": "^1.20.3",
- "compression": "^1.7.4",
- "express": "^4.20.0",
- "express-fileupload": "^1.1.9",
- "gravatar": "^1.8.0",
- "jsonwebtoken": "^9.0.0",
- "knex": "2.4.2",
- "liquidjs": "10.6.1",
- "lodash": "^4.17.21",
- "moment": "^2.29.4",
- "mysql2": "^3.11.1",
- "node-rsa": "^1.0.8",
- "objection": "3.0.1",
- "path": "^0.12.7",
- "pg": "^8.13.1",
- "signale": "1.4.0",
- "sqlite3": "5.1.6",
- "temp-write": "^4.0.0"
- },
- "signale": {
- "displayDate": true,
- "displayTimestamp": true
- },
- "author": "Jamie Curnow ",
- "license": "MIT",
- "devDependencies": {
- "@apidevtools/swagger-parser": "^10.1.0",
- "chalk": "4.1.2",
- "eslint": "^8.36.0",
- "eslint-plugin-align-assignments": "^1.1.2",
- "nodemon": "^2.0.2",
- "prettier": "^2.0.4"
- },
- "scripts": {
- "validate-schema": "node validate-schema.js"
- }
-}
diff --git a/backend/routes/audit-log.js b/backend/routes/audit-log.js
deleted file mode 100644
index c68c7b35..00000000
--- a/backend/routes/audit-log.js
+++ /dev/null
@@ -1,52 +0,0 @@
-const express = require('express');
-const validator = require('../lib/validator');
-const jwtdecode = require('../lib/express/jwt-decode');
-const internalAuditLog = require('../internal/audit-log');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/audit-log
- */
-router
- .route('/')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/audit-log
- *
- * Retrieve all logs
- */
- .get((req, res, next) => {
- validator({
- additionalProperties: false,
- properties: {
- expand: {
- $ref: 'common#/properties/expand'
- },
- query: {
- $ref: 'common#/properties/query'
- }
- }
- }, {
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null),
- query: (typeof req.query.query === 'string' ? req.query.query : null)
- })
- .then((data) => {
- return internalAuditLog.getAll(res.locals.access, data.expand, data.query);
- })
- .then((rows) => {
- res.status(200)
- .send(rows);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/main.js b/backend/routes/main.js
deleted file mode 100644
index b97096d0..00000000
--- a/backend/routes/main.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const express = require('express');
-const pjson = require('../package.json');
-const error = require('../lib/error');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * Health Check
- * GET /api
- */
-router.get('/', (req, res/*, next*/) => {
- let version = pjson.version.split('-').shift().split('.');
-
- res.status(200).send({
- status: 'OK',
- version: {
- major: parseInt(version.shift(), 10),
- minor: parseInt(version.shift(), 10),
- revision: parseInt(version.shift(), 10)
- }
- });
-});
-
-router.use('/schema', require('./schema'));
-router.use('/tokens', require('./tokens'));
-router.use('/users', require('./users'));
-router.use('/audit-log', require('./audit-log'));
-router.use('/reports', require('./reports'));
-router.use('/settings', require('./settings'));
-router.use('/nginx/proxy-hosts', require('./nginx/proxy_hosts'));
-router.use('/nginx/redirection-hosts', require('./nginx/redirection_hosts'));
-router.use('/nginx/dead-hosts', require('./nginx/dead_hosts'));
-router.use('/nginx/streams', require('./nginx/streams'));
-router.use('/nginx/access-lists', require('./nginx/access_lists'));
-router.use('/nginx/certificates', require('./nginx/certificates'));
-
-/**
- * API 404 for all other routes
- *
- * ALL /api/*
- */
-router.all(/(.+)/, function (req, _, next) {
- req.params.page = req.params['0'];
- next(new error.ItemNotFoundError(req.params.page));
-});
-
-module.exports = router;
diff --git a/backend/routes/nginx/access_lists.js b/backend/routes/nginx/access_lists.js
deleted file mode 100644
index 38375127..00000000
--- a/backend/routes/nginx/access_lists.js
+++ /dev/null
@@ -1,149 +0,0 @@
-const express = require('express');
-const validator = require('../../lib/validator');
-const jwtdecode = require('../../lib/express/jwt-decode');
-const apiValidator = require('../../lib/validator/api');
-const internalAccessList = require('../../internal/access-list');
-const schema = require('../../schema');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/nginx/access-lists
- */
-router
- .route('/')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/access-lists
- *
- * Retrieve all access-lists
- */
- .get((req, res, next) => {
- validator({
- additionalProperties: false,
- properties: {
- expand: {
- $ref: 'common#/properties/expand'
- },
- query: {
- $ref: 'common#/properties/query'
- }
- }
- }, {
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null),
- query: (typeof req.query.query === 'string' ? req.query.query : null)
- })
- .then((data) => {
- return internalAccessList.getAll(res.locals.access, data.expand, data.query);
- })
- .then((rows) => {
- res.status(200)
- .send(rows);
- })
- .catch(next);
- })
-
- /**
- * POST /api/nginx/access-lists
- *
- * Create a new access-list
- */
- .post((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/access-lists', 'post'), req.body)
- .then((payload) => {
- return internalAccessList.create(res.locals.access, payload);
- })
- .then((result) => {
- res.status(201)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific access-list
- *
- * /api/nginx/access-lists/123
- */
-router
- .route('/:list_id')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/access-lists/123
- *
- * Retrieve a specific access-list
- */
- .get((req, res, next) => {
- validator({
- required: ['list_id'],
- additionalProperties: false,
- properties: {
- list_id: {
- $ref: 'common#/properties/id'
- },
- expand: {
- $ref: 'common#/properties/expand'
- }
- }
- }, {
- list_id: req.params.list_id,
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null)
- })
- .then((data) => {
- return internalAccessList.get(res.locals.access, {
- id: parseInt(data.list_id, 10),
- expand: data.expand
- });
- })
- .then((row) => {
- res.status(200)
- .send(row);
- })
- .catch(next);
- })
-
- /**
- * PUT /api/nginx/access-lists/123
- *
- * Update and existing access-list
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/access-lists/{listID}', 'put'), req.body)
- .then((payload) => {
- payload.id = parseInt(req.params.list_id, 10);
- return internalAccessList.update(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- })
-
- /**
- * DELETE /api/nginx/access-lists/123
- *
- * Delete and existing access-list
- */
- .delete((req, res, next) => {
- internalAccessList.delete(res.locals.access, {id: parseInt(req.params.list_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/nginx/certificates.js b/backend/routes/nginx/certificates.js
deleted file mode 100644
index 4b10d137..00000000
--- a/backend/routes/nginx/certificates.js
+++ /dev/null
@@ -1,288 +0,0 @@
-const express = require('express');
-const error = require('../../lib/error');
-const validator = require('../../lib/validator');
-const jwtdecode = require('../../lib/express/jwt-decode');
-const apiValidator = require('../../lib/validator/api');
-const internalCertificate = require('../../internal/certificate');
-const schema = require('../../schema');
-
-const router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/nginx/certificates
- */
-router
- .route('/')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/certificates
- *
- * Retrieve all certificates
- */
- .get((req, res, next) => {
- validator({
- additionalProperties: false,
- properties: {
- expand: {
- $ref: 'common#/properties/expand'
- },
- query: {
- $ref: 'common#/properties/query'
- }
- }
- }, {
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null),
- query: (typeof req.query.query === 'string' ? req.query.query : null)
- })
- .then((data) => {
- return internalCertificate.getAll(res.locals.access, data.expand, data.query);
- })
- .then((rows) => {
- res.status(200)
- .send(rows);
- })
- .catch(next);
- })
-
- /**
- * POST /api/nginx/certificates
- *
- * Create a new certificate
- */
- .post((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/certificates', 'post'), req.body)
- .then((payload) => {
- req.setTimeout(900000); // 15 minutes timeout
- return internalCertificate.create(res.locals.access, payload);
- })
- .then((result) => {
- res.status(201)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Test HTTP challenge for domains
- *
- * /api/nginx/certificates/test-http
- */
-router
- .route('/test-http')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/certificates/test-http
- *
- * Test HTTP challenge for domains
- */
- .get((req, res, next) => {
- if (req.query.domains === undefined) {
- next(new error.ValidationError('Domains are required as query parameters'));
- return;
- }
-
- internalCertificate.testHttpsChallenge(res.locals.access, JSON.parse(req.query.domains))
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific certificate
- *
- * /api/nginx/certificates/123
- */
-router
- .route('/:certificate_id')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/certificates/123
- *
- * Retrieve a specific certificate
- */
- .get((req, res, next) => {
- validator({
- required: ['certificate_id'],
- additionalProperties: false,
- properties: {
- certificate_id: {
- $ref: 'common#/properties/id'
- },
- expand: {
- $ref: 'common#/properties/expand'
- }
- }
- }, {
- certificate_id: req.params.certificate_id,
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null)
- })
- .then((data) => {
- return internalCertificate.get(res.locals.access, {
- id: parseInt(data.certificate_id, 10),
- expand: data.expand
- });
- })
- .then((row) => {
- res.status(200)
- .send(row);
- })
- .catch(next);
- })
-
- /**
- * DELETE /api/nginx/certificates/123
- *
- * Update and existing certificate
- */
- .delete((req, res, next) => {
- internalCertificate.delete(res.locals.access, {id: parseInt(req.params.certificate_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Upload Certs
- *
- * /api/nginx/certificates/123/upload
- */
-router
- .route('/:certificate_id/upload')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/certificates/123/upload
- *
- * Upload certificates
- */
- .post((req, res, next) => {
- if (!req.files) {
- res.status(400)
- .send({error: 'No files were uploaded'});
- } else {
- internalCertificate.upload(res.locals.access, {
- id: parseInt(req.params.certificate_id, 10),
- files: req.files
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- }
- });
-
-/**
- * Renew LE Certs
- *
- * /api/nginx/certificates/123/renew
- */
-router
- .route('/:certificate_id/renew')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/certificates/123/renew
- *
- * Renew certificate
- */
- .post((req, res, next) => {
- req.setTimeout(900000); // 15 minutes timeout
- internalCertificate.renew(res.locals.access, {
- id: parseInt(req.params.certificate_id, 10)
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Download LE Certs
- *
- * /api/nginx/certificates/123/download
- */
-router
- .route('/:certificate_id/download')
- .options((_req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/certificates/123/download
- *
- * Renew certificate
- */
- .get((req, res, next) => {
- internalCertificate.download(res.locals.access, {
- id: parseInt(req.params.certificate_id, 10)
- })
- .then((result) => {
- res.status(200)
- .download(result.fileName);
- })
- .catch(next);
- });
-
-/**
- * Validate Certs before saving
- *
- * /api/nginx/certificates/validate
- */
-router
- .route('/validate')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/certificates/validate
- *
- * Validate certificates
- */
- .post((req, res, next) => {
- if (!req.files) {
- res.status(400)
- .send({error: 'No files were uploaded'});
- } else {
- internalCertificate.validate({
- files: req.files
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- }
- });
-
-module.exports = router;
diff --git a/backend/routes/nginx/dead_hosts.js b/backend/routes/nginx/dead_hosts.js
deleted file mode 100644
index 83b37765..00000000
--- a/backend/routes/nginx/dead_hosts.js
+++ /dev/null
@@ -1,197 +0,0 @@
-const express = require('express');
-const validator = require('../../lib/validator');
-const jwtdecode = require('../../lib/express/jwt-decode');
-const apiValidator = require('../../lib/validator/api');
-const internalDeadHost = require('../../internal/dead-host');
-const schema = require('../../schema');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/nginx/dead-hosts
- */
-router
- .route('/')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/dead-hosts
- *
- * Retrieve all dead-hosts
- */
- .get((req, res, next) => {
- validator({
- additionalProperties: false,
- properties: {
- expand: {
- $ref: 'common#/properties/expand'
- },
- query: {
- $ref: 'common#/properties/query'
- }
- }
- }, {
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null),
- query: (typeof req.query.query === 'string' ? req.query.query : null)
- })
- .then((data) => {
- return internalDeadHost.getAll(res.locals.access, data.expand, data.query);
- })
- .then((rows) => {
- res.status(200)
- .send(rows);
- })
- .catch(next);
- })
-
- /**
- * POST /api/nginx/dead-hosts
- *
- * Create a new dead-host
- */
- .post((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/dead-hosts', 'post'), req.body)
- .then((payload) => {
- return internalDeadHost.create(res.locals.access, payload);
- })
- .then((result) => {
- res.status(201)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific dead-host
- *
- * /api/nginx/dead-hosts/123
- */
-router
- .route('/:host_id')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/dead-hosts/123
- *
- * Retrieve a specific dead-host
- */
- .get((req, res, next) => {
- validator({
- required: ['host_id'],
- additionalProperties: false,
- properties: {
- host_id: {
- $ref: 'common#/properties/id'
- },
- expand: {
- $ref: 'common#/properties/expand'
- }
- }
- }, {
- host_id: req.params.host_id,
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null)
- })
- .then((data) => {
- return internalDeadHost.get(res.locals.access, {
- id: parseInt(data.host_id, 10),
- expand: data.expand
- });
- })
- .then((row) => {
- res.status(200)
- .send(row);
- })
- .catch(next);
- })
-
- /**
- * PUT /api/nginx/dead-hosts/123
- *
- * Update and existing dead-host
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/dead-hosts/{hostID}', 'put'), req.body)
- .then((payload) => {
- payload.id = parseInt(req.params.host_id, 10);
- return internalDeadHost.update(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- })
-
- /**
- * DELETE /api/nginx/dead-hosts/123
- *
- * Update and existing dead-host
- */
- .delete((req, res, next) => {
- internalDeadHost.delete(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Enable dead-host
- *
- * /api/nginx/dead-hosts/123/enable
- */
-router
- .route('/:host_id/enable')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/dead-hosts/123/enable
- */
- .post((req, res, next) => {
- internalDeadHost.enable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Disable dead-host
- *
- * /api/nginx/dead-hosts/123/disable
- */
-router
- .route('/:host_id/disable')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/dead-hosts/123/disable
- */
- .post((req, res, next) => {
- internalDeadHost.disable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/nginx/proxy_hosts.js b/backend/routes/nginx/proxy_hosts.js
deleted file mode 100644
index 3be4582a..00000000
--- a/backend/routes/nginx/proxy_hosts.js
+++ /dev/null
@@ -1,197 +0,0 @@
-const express = require('express');
-const validator = require('../../lib/validator');
-const jwtdecode = require('../../lib/express/jwt-decode');
-const apiValidator = require('../../lib/validator/api');
-const internalProxyHost = require('../../internal/proxy-host');
-const schema = require('../../schema');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/nginx/proxy-hosts
- */
-router
- .route('/')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/proxy-hosts
- *
- * Retrieve all proxy-hosts
- */
- .get((req, res, next) => {
- validator({
- additionalProperties: false,
- properties: {
- expand: {
- $ref: 'common#/properties/expand'
- },
- query: {
- $ref: 'common#/properties/query'
- }
- }
- }, {
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null),
- query: (typeof req.query.query === 'string' ? req.query.query : null)
- })
- .then((data) => {
- return internalProxyHost.getAll(res.locals.access, data.expand, data.query);
- })
- .then((rows) => {
- res.status(200)
- .send(rows);
- })
- .catch(next);
- })
-
- /**
- * POST /api/nginx/proxy-hosts
- *
- * Create a new proxy-host
- */
- .post((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/proxy-hosts', 'post'), req.body)
- .then((payload) => {
- return internalProxyHost.create(res.locals.access, payload);
- })
- .then((result) => {
- res.status(201)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific proxy-host
- *
- * /api/nginx/proxy-hosts/123
- */
-router
- .route('/:host_id')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/proxy-hosts/123
- *
- * Retrieve a specific proxy-host
- */
- .get((req, res, next) => {
- validator({
- required: ['host_id'],
- additionalProperties: false,
- properties: {
- host_id: {
- $ref: 'common#/properties/id'
- },
- expand: {
- $ref: 'common#/properties/expand'
- }
- }
- }, {
- host_id: req.params.host_id,
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null)
- })
- .then((data) => {
- return internalProxyHost.get(res.locals.access, {
- id: parseInt(data.host_id, 10),
- expand: data.expand
- });
- })
- .then((row) => {
- res.status(200)
- .send(row);
- })
- .catch(next);
- })
-
- /**
- * PUT /api/nginx/proxy-hosts/123
- *
- * Update and existing proxy-host
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/proxy-hosts/{hostID}', 'put'), req.body)
- .then((payload) => {
- payload.id = parseInt(req.params.host_id, 10);
- return internalProxyHost.update(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- })
-
- /**
- * DELETE /api/nginx/proxy-hosts/123
- *
- * Update and existing proxy-host
- */
- .delete((req, res, next) => {
- internalProxyHost.delete(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Enable proxy-host
- *
- * /api/nginx/proxy-hosts/123/enable
- */
-router
- .route('/:host_id/enable')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/proxy-hosts/123/enable
- */
- .post((req, res, next) => {
- internalProxyHost.enable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Disable proxy-host
- *
- * /api/nginx/proxy-hosts/123/disable
- */
-router
- .route('/:host_id/disable')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/proxy-hosts/123/disable
- */
- .post((req, res, next) => {
- internalProxyHost.disable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/nginx/redirection_hosts.js b/backend/routes/nginx/redirection_hosts.js
deleted file mode 100644
index a46feb84..00000000
--- a/backend/routes/nginx/redirection_hosts.js
+++ /dev/null
@@ -1,197 +0,0 @@
-const express = require('express');
-const validator = require('../../lib/validator');
-const jwtdecode = require('../../lib/express/jwt-decode');
-const apiValidator = require('../../lib/validator/api');
-const internalRedirectionHost = require('../../internal/redirection-host');
-const schema = require('../../schema');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/nginx/redirection-hosts
- */
-router
- .route('/')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/redirection-hosts
- *
- * Retrieve all redirection-hosts
- */
- .get((req, res, next) => {
- validator({
- additionalProperties: false,
- properties: {
- expand: {
- $ref: 'common#/properties/expand'
- },
- query: {
- $ref: 'common#/properties/query'
- }
- }
- }, {
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null),
- query: (typeof req.query.query === 'string' ? req.query.query : null)
- })
- .then((data) => {
- return internalRedirectionHost.getAll(res.locals.access, data.expand, data.query);
- })
- .then((rows) => {
- res.status(200)
- .send(rows);
- })
- .catch(next);
- })
-
- /**
- * POST /api/nginx/redirection-hosts
- *
- * Create a new redirection-host
- */
- .post((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/redirection-hosts', 'post'), req.body)
- .then((payload) => {
- return internalRedirectionHost.create(res.locals.access, payload);
- })
- .then((result) => {
- res.status(201)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific redirection-host
- *
- * /api/nginx/redirection-hosts/123
- */
-router
- .route('/:host_id')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/nginx/redirection-hosts/123
- *
- * Retrieve a specific redirection-host
- */
- .get((req, res, next) => {
- validator({
- required: ['host_id'],
- additionalProperties: false,
- properties: {
- host_id: {
- $ref: 'common#/properties/id'
- },
- expand: {
- $ref: 'common#/properties/expand'
- }
- }
- }, {
- host_id: req.params.host_id,
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null)
- })
- .then((data) => {
- return internalRedirectionHost.get(res.locals.access, {
- id: parseInt(data.host_id, 10),
- expand: data.expand
- });
- })
- .then((row) => {
- res.status(200)
- .send(row);
- })
- .catch(next);
- })
-
- /**
- * PUT /api/nginx/redirection-hosts/123
- *
- * Update and existing redirection-host
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/redirection-hosts/{hostID}', 'put'), req.body)
- .then((payload) => {
- payload.id = parseInt(req.params.host_id, 10);
- return internalRedirectionHost.update(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- })
-
- /**
- * DELETE /api/nginx/redirection-hosts/123
- *
- * Update and existing redirection-host
- */
- .delete((req, res, next) => {
- internalRedirectionHost.delete(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Enable redirection-host
- *
- * /api/nginx/redirection-hosts/123/enable
- */
-router
- .route('/:host_id/enable')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/redirection-hosts/123/enable
- */
- .post((req, res, next) => {
- internalRedirectionHost.enable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Disable redirection-host
- *
- * /api/nginx/redirection-hosts/123/disable
- */
-router
- .route('/:host_id/disable')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/redirection-hosts/123/disable
- */
- .post((req, res, next) => {
- internalRedirectionHost.disable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/nginx/streams.js b/backend/routes/nginx/streams.js
deleted file mode 100644
index c033f2ef..00000000
--- a/backend/routes/nginx/streams.js
+++ /dev/null
@@ -1,197 +0,0 @@
-const express = require('express');
-const validator = require('../../lib/validator');
-const jwtdecode = require('../../lib/express/jwt-decode');
-const apiValidator = require('../../lib/validator/api');
-const internalStream = require('../../internal/stream');
-const schema = require('../../schema');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/nginx/streams
- */
-router
- .route('/')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes
-
- /**
- * GET /api/nginx/streams
- *
- * Retrieve all streams
- */
- .get((req, res, next) => {
- validator({
- additionalProperties: false,
- properties: {
- expand: {
- $ref: 'common#/properties/expand'
- },
- query: {
- $ref: 'common#/properties/query'
- }
- }
- }, {
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null),
- query: (typeof req.query.query === 'string' ? req.query.query : null)
- })
- .then((data) => {
- return internalStream.getAll(res.locals.access, data.expand, data.query);
- })
- .then((rows) => {
- res.status(200)
- .send(rows);
- })
- .catch(next);
- })
-
- /**
- * POST /api/nginx/streams
- *
- * Create a new stream
- */
- .post((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/streams', 'post'), req.body)
- .then((payload) => {
- return internalStream.create(res.locals.access, payload);
- })
- .then((result) => {
- res.status(201)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific stream
- *
- * /api/nginx/streams/123
- */
-router
- .route('/:stream_id')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode()) // preferred so it doesn't apply to nonexistent routes
-
- /**
- * GET /api/nginx/streams/123
- *
- * Retrieve a specific stream
- */
- .get((req, res, next) => {
- validator({
- required: ['stream_id'],
- additionalProperties: false,
- properties: {
- stream_id: {
- $ref: 'common#/properties/id'
- },
- expand: {
- $ref: 'common#/properties/expand'
- }
- }
- }, {
- stream_id: req.params.stream_id,
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null)
- })
- .then((data) => {
- return internalStream.get(res.locals.access, {
- id: parseInt(data.stream_id, 10),
- expand: data.expand
- });
- })
- .then((row) => {
- res.status(200)
- .send(row);
- })
- .catch(next);
- })
-
- /**
- * PUT /api/nginx/streams/123
- *
- * Update and existing stream
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/nginx/streams/{streamID}', 'put'), req.body)
- .then((payload) => {
- payload.id = parseInt(req.params.stream_id, 10);
- return internalStream.update(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- })
-
- /**
- * DELETE /api/nginx/streams/123
- *
- * Update and existing stream
- */
- .delete((req, res, next) => {
- internalStream.delete(res.locals.access, {id: parseInt(req.params.stream_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Enable stream
- *
- * /api/nginx/streams/123/enable
- */
-router
- .route('/:host_id/enable')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/streams/123/enable
- */
- .post((req, res, next) => {
- internalStream.enable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Disable stream
- *
- * /api/nginx/streams/123/disable
- */
-router
- .route('/:host_id/disable')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/nginx/streams/123/disable
- */
- .post((req, res, next) => {
- internalStream.disable(res.locals.access, {id: parseInt(req.params.host_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/reports.js b/backend/routes/reports.js
deleted file mode 100644
index 98c6cf86..00000000
--- a/backend/routes/reports.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const express = require('express');
-const jwtdecode = require('../lib/express/jwt-decode');
-const internalReport = require('../internal/report');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-router
- .route('/hosts')
- .options((_, res) => {
- res.sendStatus(204);
- })
-
- /**
- * GET /reports/hosts
- */
- .get(jwtdecode(), (_, res, next) => {
- internalReport.getHostsReport(res.locals.access)
- .then((data) => {
- res.status(200)
- .send(data);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/schema.js b/backend/routes/schema.js
deleted file mode 100644
index fc3e48b6..00000000
--- a/backend/routes/schema.js
+++ /dev/null
@@ -1,38 +0,0 @@
-const express = require('express');
-const schema = require('../schema');
-const PACKAGE = require('../package.json');
-
-const router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-router
- .route('/')
- .options((_, res) => {
- res.sendStatus(204);
- })
-
- /**
- * GET /schema
- */
- .get(async (req, res) => {
- let swaggerJSON = await schema.getCompiledSchema();
-
- let proto = req.protocol;
- if (typeof req.headers['x-forwarded-proto'] !== 'undefined' && req.headers['x-forwarded-proto']) {
- proto = req.headers['x-forwarded-proto'];
- }
-
- let origin = proto + '://' + req.hostname;
- if (typeof req.headers.origin !== 'undefined' && req.headers.origin) {
- origin = req.headers.origin;
- }
-
- swaggerJSON.info.version = PACKAGE.version;
- swaggerJSON.servers[0].url = origin + '/api';
- res.status(200).send(swaggerJSON);
- });
-
-module.exports = router;
diff --git a/backend/routes/settings.js b/backend/routes/settings.js
deleted file mode 100644
index dac4c3d1..00000000
--- a/backend/routes/settings.js
+++ /dev/null
@@ -1,98 +0,0 @@
-const express = require('express');
-const validator = require('../lib/validator');
-const jwtdecode = require('../lib/express/jwt-decode');
-const apiValidator = require('../lib/validator/api');
-const internalSetting = require('../internal/setting');
-const schema = require('../schema');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/settings
- */
-router
- .route('/')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/settings
- *
- * Retrieve all settings
- */
- .get((_, res, next) => {
- internalSetting.getAll(res.locals.access)
- .then((rows) => {
- res.status(200)
- .send(rows);
- })
- .catch(next);
- });
-
-/**
- * Specific setting
- *
- * /api/settings/something
- */
-router
- .route('/:setting_id')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /settings/something
- *
- * Retrieve a specific setting
- */
- .get((req, res, next) => {
- validator({
- required: ['setting_id'],
- additionalProperties: false,
- properties: {
- setting_id: {
- type: 'string',
- minLength: 1
- }
- }
- }, {
- setting_id: req.params.setting_id
- })
- .then((data) => {
- return internalSetting.get(res.locals.access, {
- id: data.setting_id
- });
- })
- .then((row) => {
- res.status(200)
- .send(row);
- })
- .catch(next);
- })
-
- /**
- * PUT /api/settings/something
- *
- * Update and existing setting
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/settings/{settingID}', 'put'), req.body)
- .then((payload) => {
- payload.id = req.params.setting_id;
- return internalSetting.update(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/tokens.js b/backend/routes/tokens.js
deleted file mode 100644
index 72d01d41..00000000
--- a/backend/routes/tokens.js
+++ /dev/null
@@ -1,53 +0,0 @@
-const express = require('express');
-const jwtdecode = require('../lib/express/jwt-decode');
-const apiValidator = require('../lib/validator/api');
-const internalToken = require('../internal/token');
-const schema = require('../schema');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-router
- .route('/')
- .options((_, res) => {
- res.sendStatus(204);
- })
-
- /**
- * GET /tokens
- *
- * Get a new Token, given they already have a token they want to refresh
- * We also piggy back on to this method, allowing admins to get tokens
- * for services like Job board and Worker.
- */
- .get(jwtdecode(), (req, res, next) => {
- internalToken.getFreshToken(res.locals.access, {
- expiry: (typeof req.query.expiry !== 'undefined' ? req.query.expiry : null),
- scope: (typeof req.query.scope !== 'undefined' ? req.query.scope : null)
- })
- .then((data) => {
- res.status(200)
- .send(data);
- })
- .catch(next);
- })
-
- /**
- * POST /tokens
- *
- * Create a new Token
- */
- .post(async (req, res, next) => {
- apiValidator(schema.getValidationSchema('/tokens', 'post'), req.body)
- .then(internalToken.getTokenFromEmail)
- .then((data) => {
- res.status(200)
- .send(data);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/routes/users.js b/backend/routes/users.js
deleted file mode 100644
index e41bf6cf..00000000
--- a/backend/routes/users.js
+++ /dev/null
@@ -1,247 +0,0 @@
-const express = require('express');
-const validator = require('../lib/validator');
-const jwtdecode = require('../lib/express/jwt-decode');
-const userIdFromMe = require('../lib/express/user-id-from-me');
-const internalUser = require('../internal/user');
-const apiValidator = require('../lib/validator/api');
-const schema = require('../schema');
-
-let router = express.Router({
- caseSensitive: true,
- strict: true,
- mergeParams: true
-});
-
-/**
- * /api/users
- */
-router
- .route('/')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * GET /api/users
- *
- * Retrieve all users
- */
- .get((req, res, next) => {
- validator({
- additionalProperties: false,
- properties: {
- expand: {
- $ref: 'common#/properties/expand'
- },
- query: {
- $ref: 'common#/properties/query'
- }
- }
- }, {
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null),
- query: (typeof req.query.query === 'string' ? req.query.query : null)
- })
- .then((data) => {
- return internalUser.getAll(res.locals.access, data.expand, data.query);
- })
- .then((users) => {
- res.status(200)
- .send(users);
- })
- .catch((err) => {
- console.log(err);
- next(err);
- });
- //.catch(next);
- })
-
- /**
- * POST /api/users
- *
- * Create a new User
- */
- .post((req, res, next) => {
- apiValidator(schema.getValidationSchema('/users', 'post'), req.body)
- .then((payload) => {
- return internalUser.create(res.locals.access, payload);
- })
- .then((result) => {
- res.status(201)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific user
- *
- * /api/users/123
- */
-router
- .route('/:user_id')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
- .all(userIdFromMe)
-
- /**
- * GET /users/123 or /users/me
- *
- * Retrieve a specific user
- */
- .get((req, res, next) => {
- validator({
- required: ['user_id'],
- additionalProperties: false,
- properties: {
- user_id: {
- $ref: 'common#/properties/id'
- },
- expand: {
- $ref: 'common#/properties/expand'
- }
- }
- }, {
- user_id: req.params.user_id,
- expand: (typeof req.query.expand === 'string' ? req.query.expand.split(',') : null)
- })
- .then((data) => {
- return internalUser.get(res.locals.access, {
- id: data.user_id,
- expand: data.expand,
- omit: internalUser.getUserOmisionsByAccess(res.locals.access, data.user_id)
- });
- })
- .then((user) => {
- res.status(200)
- .send(user);
- })
- .catch((err) => {
- console.log(err);
- next(err);
- });
- })
-
- /**
- * PUT /api/users/123
- *
- * Update and existing user
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/users/{userID}', 'put'), req.body)
- .then((payload) => {
- payload.id = req.params.user_id;
- return internalUser.update(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- })
-
- /**
- * DELETE /api/users/123
- *
- * Update and existing user
- */
- .delete((req, res, next) => {
- internalUser.delete(res.locals.access, {id: req.params.user_id})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific user auth
- *
- * /api/users/123/auth
- */
-router
- .route('/:user_id/auth')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
- .all(userIdFromMe)
-
- /**
- * PUT /api/users/123/auth
- *
- * Update password for a user
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/users/{userID}/auth', 'put'), req.body)
- .then((payload) => {
- payload.id = req.params.user_id;
- return internalUser.setPassword(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific user permissions
- *
- * /api/users/123/permissions
- */
-router
- .route('/:user_id/permissions')
- .options((req, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
- .all(userIdFromMe)
-
- /**
- * PUT /api/users/123/permissions
- *
- * Set some or all permissions for a user
- */
- .put((req, res, next) => {
- apiValidator(schema.getValidationSchema('/users/{userID}/permissions', 'put'), req.body)
- .then((payload) => {
- payload.id = req.params.user_id;
- return internalUser.setPermissions(res.locals.access, payload);
- })
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-/**
- * Specific user login as
- *
- * /api/users/123/login
- */
-router
- .route('/:user_id/login')
- .options((_, res) => {
- res.sendStatus(204);
- })
- .all(jwtdecode())
-
- /**
- * POST /api/users/123/login
- *
- * Log in as a user
- */
- .post((req, res, next) => {
- internalUser.loginAs(res.locals.access, {id: parseInt(req.params.user_id, 10)})
- .then((result) => {
- res.status(200)
- .send(result);
- })
- .catch(next);
- });
-
-module.exports = router;
diff --git a/backend/schema/common.json b/backend/schema/common.json
deleted file mode 100644
index 343f125e..00000000
--- a/backend/schema/common.json
+++ /dev/null
@@ -1,120 +0,0 @@
-{
- "$schema": "https://json-schema.org/draft/2020-12/schema",
- "$id": "common",
- "type": "object",
- "properties": {
- "id": {
- "description": "Unique identifier",
- "readOnly": true,
- "type": "integer",
- "minimum": 1
- },
- "expand": {
- "anyOf": [
- {
- "type": "null"
- },
- {
- "type": "array",
- "minItems": 1,
- "items": {
- "type": "string"
- }
- }
- ]
- },
- "query": {
- "anyOf": [
- {
- "type": "null"
- },
- {
- "type": "string",
- "minLength": 1,
- "maxLength": 255
- }
- ]
- },
- "created_on": {
- "description": "Date and time of creation",
- "readOnly": true,
- "type": "string"
- },
- "modified_on": {
- "description": "Date and time of last update",
- "readOnly": true,
- "type": "string"
- },
- "user_id": {
- "description": "User ID",
- "type": "integer",
- "minimum": 1
- },
- "certificate_id": {
- "description": "Certificate ID",
- "anyOf": [
- {
- "type": "integer",
- "minimum": 0
- },
- {
- "type": "string",
- "pattern": "^new$"
- }
- ]
- },
- "access_list_id": {
- "description": "Access List ID",
- "type": "integer",
- "minimum": 0
- },
- "domain_names": {
- "description": "Domain Names separated by a comma",
- "type": "array",
- "minItems": 1,
- "maxItems": 100,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[^&| @!#%^();:/\\\\}{=+?<>,~`'\"]+$"
- }
- },
- "enabled": {
- "description": "Is Enabled",
- "type": "boolean"
- },
- "ssl_forced": {
- "description": "Is SSL Forced",
- "type": "boolean"
- },
- "hsts_enabled": {
- "description": "Is HSTS Enabled",
- "type": "boolean"
- },
- "hsts_subdomains": {
- "description": "Is HSTS applicable to all subdomains",
- "type": "boolean"
- },
- "ssl_provider": {
- "type": "string",
- "pattern": "^(letsencrypt|other)$"
- },
- "http2_support": {
- "description": "HTTP2 Protocol Support",
- "type": "boolean"
- },
- "block_exploits": {
- "description": "Should we block common exploits",
- "type": "boolean"
- },
- "caching_enabled": {
- "description": "Should we cache assets",
- "type": "boolean"
- },
- "email": {
- "description": "Email address",
- "type": "string",
- "pattern": "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
- }
- }
-}
diff --git a/backend/schema/components/access-list-object.json b/backend/schema/components/access-list-object.json
deleted file mode 100644
index cd0218d7..00000000
--- a/backend/schema/components/access-list-object.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "type": "object",
- "description": "Access List object",
- "required": ["id", "created_on", "modified_on", "owner_user_id", "name", "directive", "address", "satisfy_any", "pass_auth", "meta"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "$ref": "../common.json#/properties/id"
- },
- "created_on": {
- "$ref": "../common.json#/properties/created_on"
- },
- "modified_on": {
- "$ref": "../common.json#/properties/modified_on"
- },
- "owner_user_id": {
- "$ref": "../common.json#/properties/user_id"
- },
- "name": {
- "type": "string",
- "minLength": 1
- },
- "directive": {
- "type": "string",
- "enum": ["allow", "deny"]
- },
- "address": {
- "oneOf": [
- {
- "type": "string",
- "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$"
- },
- {
- "type": "string",
- "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"
- },
- {
- "type": "string",
- "pattern": "^all$"
- }
- ]
- },
- "satisfy_any": {
- "type": "boolean"
- },
- "pass_auth": {
- "type": "boolean"
- },
- "meta": {
- "type": "object"
- }
- }
-}
diff --git a/backend/schema/components/audit-log-object.json b/backend/schema/components/audit-log-object.json
deleted file mode 100644
index 3e5e8594..00000000
--- a/backend/schema/components/audit-log-object.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "type": "object",
- "description": "Audit Log object",
- "required": ["id", "created_on", "modified_on", "user_id", "object_type", "object_id", "action", "meta"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "$ref": "../common.json#/properties/id"
- },
- "created_on": {
- "$ref": "../common.json#/properties/created_on"
- },
- "modified_on": {
- "$ref": "../common.json#/properties/modified_on"
- },
- "user_id": {
- "$ref": "../common.json#/properties/user_id"
- },
- "object_type": {
- "type": "string"
- },
- "object_id": {
- "$ref": "../common.json#/properties/id"
- },
- "action": {
- "type": "string"
- },
- "meta": {
- "type": "object"
- }
- }
-}
diff --git a/backend/schema/components/certificate-list.json b/backend/schema/components/certificate-list.json
deleted file mode 100644
index cec4db82..00000000
--- a/backend/schema/components/certificate-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "array",
- "description": "Certificates list",
- "items": {
- "$ref": "./certificate-object.json"
- }
-}
diff --git a/backend/schema/components/certificate-object.json b/backend/schema/components/certificate-object.json
deleted file mode 100644
index dcc2a834..00000000
--- a/backend/schema/components/certificate-object.json
+++ /dev/null
@@ -1,81 +0,0 @@
-{
- "type": "object",
- "description": "Certificate object",
- "required": ["id", "created_on", "modified_on", "owner_user_id", "provider", "nice_name", "domain_names", "expires_on", "meta"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "$ref": "../common.json#/properties/id"
- },
- "created_on": {
- "$ref": "../common.json#/properties/created_on"
- },
- "modified_on": {
- "$ref": "../common.json#/properties/modified_on"
- },
- "owner_user_id": {
- "$ref": "../common.json#/properties/user_id"
- },
- "provider": {
- "$ref": "../common.json#/properties/ssl_provider"
- },
- "nice_name": {
- "type": "string",
- "description": "Nice Name for the custom certificate"
- },
- "domain_names": {
- "description": "Domain Names separated by a comma",
- "type": "array",
- "maxItems": 100,
- "uniqueItems": true,
- "items": {
- "type": "string",
- "pattern": "^[^&| @!#%^();:/\\\\}{=+?<>,~`'\"]+$"
- }
- },
- "expires_on": {
- "description": "Date and time of expiration",
- "readOnly": true,
- "type": "string"
- },
- "owner": {
- "$ref": "./user-object.json"
- },
- "meta": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "certificate": {
- "type": "string",
- "minLength": 1
- },
- "certificate_key": {
- "type": "string",
- "minLength": 1
- },
- "dns_challenge": {
- "type": "boolean"
- },
- "dns_provider": {
- "type": "string"
- },
- "dns_provider_credentials": {
- "type": "string"
- },
- "letsencrypt_agree": {
- "type": "boolean"
- },
- "letsencrypt_certificate": {
- "type": "object"
- },
- "letsencrypt_email": {
- "$ref": "../common.json#/properties/email"
- },
- "propagation_seconds": {
- "type": "integer",
- "minimum": 0
- }
- }
- }
- }
-}
diff --git a/backend/schema/components/dead-host-list.json b/backend/schema/components/dead-host-list.json
deleted file mode 100644
index 56ff303b..00000000
--- a/backend/schema/components/dead-host-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "array",
- "description": "404 Hosts list",
- "items": {
- "$ref": "./dead-host-object.json"
- }
-}
diff --git a/backend/schema/components/dead-host-object.json b/backend/schema/components/dead-host-object.json
deleted file mode 100644
index 792c2f81..00000000
--- a/backend/schema/components/dead-host-object.json
+++ /dev/null
@@ -1,47 +0,0 @@
-{
- "type": "object",
- "description": "404 Host object",
- "required": ["id", "created_on", "modified_on", "owner_user_id", "domain_names", "certificate_id", "ssl_forced", "hsts_enabled", "hsts_subdomains", "http2_support", "advanced_config", "enabled", "meta"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "$ref": "../common.json#/properties/id"
- },
- "created_on": {
- "$ref": "../common.json#/properties/created_on"
- },
- "modified_on": {
- "$ref": "../common.json#/properties/modified_on"
- },
- "owner_user_id": {
- "$ref": "../common.json#/properties/user_id"
- },
- "domain_names": {
- "$ref": "../common.json#/properties/domain_names"
- },
- "certificate_id": {
- "$ref": "../common.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../common.json#/properties/ssl_forced"
- },
- "hsts_enabled": {
- "$ref": "../common.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../common.json#/properties/hsts_subdomains"
- },
- "http2_support": {
- "$ref": "../common.json#/properties/http2_support"
- },
- "advanced_config": {
- "type": "string"
- },
- "enabled": {
- "$ref": "../common.json#/properties/enabled"
- },
- "meta": {
- "type": "object"
- }
- }
-}
diff --git a/backend/schema/components/error-object.json b/backend/schema/components/error-object.json
deleted file mode 100644
index c2540cf1..00000000
--- a/backend/schema/components/error-object.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "type": "object",
- "description": "Error object",
- "additionalProperties": false,
- "required": ["code", "message"],
- "properties": {
- "code": {
- "type": "integer"
- },
- "message": {
- "type": "string"
- }
- }
-}
diff --git a/backend/schema/components/error.json b/backend/schema/components/error.json
deleted file mode 100644
index ceb3e149..00000000
--- a/backend/schema/components/error.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "type": "object",
- "description": "Error",
- "properties": {
- "error": {
- "$ref": "./error-object.json"
- }
- }
-}
diff --git a/backend/schema/components/health-object.json b/backend/schema/components/health-object.json
deleted file mode 100644
index 8d223417..00000000
--- a/backend/schema/components/health-object.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "type": "object",
- "description": "Health object",
- "additionalProperties": false,
- "required": ["status", "version"],
- "properties": {
- "status": {
- "type": "string",
- "description": "Healthy",
- "example": "OK"
- },
- "version": {
- "type": "object",
- "description": "The version object",
- "example": {
- "major": 2,
- "minor": 0,
- "revision": 0
- },
- "additionalProperties": false,
- "required": ["major", "minor", "revision"],
- "properties": {
- "major": {
- "type": "integer",
- "minimum": 0
- },
- "minor": {
- "type": "integer",
- "minimum": 0
- },
- "revision": {
- "type": "integer",
- "minimum": 0
- }
- }
- }
- }
-}
diff --git a/backend/schema/components/permission-object.json b/backend/schema/components/permission-object.json
deleted file mode 100644
index b852a014..00000000
--- a/backend/schema/components/permission-object.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "type": "object",
- "minProperties": 1,
- "properties": {
- "visibility": {
- "type": "string",
- "description": "Visibility Type",
- "enum": ["all", "user"]
- },
- "access_lists": {
- "type": "string",
- "description": "Access Lists Permissions",
- "enum": ["hidden", "view", "manage"]
- },
- "dead_hosts": {
- "type": "string",
- "description": "404 Hosts Permissions",
- "enum": ["hidden", "view", "manage"]
- },
- "proxy_hosts": {
- "type": "string",
- "description": "Proxy Hosts Permissions",
- "enum": ["hidden", "view", "manage"]
- },
- "redirection_hosts": {
- "type": "string",
- "description": "Redirection Permissions",
- "enum": ["hidden", "view", "manage"]
- },
- "streams": {
- "type": "string",
- "description": "Streams Permissions",
- "enum": ["hidden", "view", "manage"]
- },
- "certificates": {
- "type": "string",
- "description": "Certificates Permissions",
- "enum": ["hidden", "view", "manage"]
- }
- }
-}
diff --git a/backend/schema/components/proxy-host-list.json b/backend/schema/components/proxy-host-list.json
deleted file mode 100644
index 39789b4a..00000000
--- a/backend/schema/components/proxy-host-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "array",
- "description": "Proxy Hosts list",
- "items": {
- "$ref": "./proxy-host-object.json"
- }
-}
diff --git a/backend/schema/components/proxy-host-object.json b/backend/schema/components/proxy-host-object.json
deleted file mode 100644
index e9dcacb5..00000000
--- a/backend/schema/components/proxy-host-object.json
+++ /dev/null
@@ -1,153 +0,0 @@
-{
- "type": "object",
- "description": "Proxy Host object",
- "required": [
- "id",
- "created_on",
- "modified_on",
- "owner_user_id",
- "domain_names",
- "forward_host",
- "forward_port",
- "access_list_id",
- "certificate_id",
- "ssl_forced",
- "caching_enabled",
- "block_exploits",
- "advanced_config",
- "meta",
- "allow_websocket_upgrade",
- "http2_support",
- "forward_scheme",
- "enabled",
- "locations",
- "hsts_enabled",
- "hsts_subdomains"
- ],
- "additionalProperties": false,
- "properties": {
- "id": {
- "$ref": "../common.json#/properties/id"
- },
- "created_on": {
- "$ref": "../common.json#/properties/created_on"
- },
- "modified_on": {
- "$ref": "../common.json#/properties/modified_on"
- },
- "owner_user_id": {
- "$ref": "../common.json#/properties/user_id"
- },
- "domain_names": {
- "$ref": "../common.json#/properties/domain_names"
- },
- "forward_host": {
- "type": "string",
- "minLength": 1,
- "maxLength": 255
- },
- "forward_port": {
- "type": "integer",
- "minimum": 1,
- "maximum": 65535
- },
- "access_list_id": {
- "$ref": "../common.json#/properties/access_list_id"
- },
- "certificate_id": {
- "$ref": "../common.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../common.json#/properties/ssl_forced"
- },
- "caching_enabled": {
- "$ref": "../common.json#/properties/caching_enabled"
- },
- "block_exploits": {
- "$ref": "../common.json#/properties/block_exploits"
- },
- "advanced_config": {
- "type": "string"
- },
- "meta": {
- "type": "object"
- },
- "allow_websocket_upgrade": {
- "description": "Allow Websocket Upgrade for all paths",
- "example": true,
- "type": "boolean"
- },
- "http2_support": {
- "$ref": "../common.json#/properties/http2_support"
- },
- "forward_scheme": {
- "type": "string",
- "enum": ["http", "https"]
- },
- "enabled": {
- "$ref": "../common.json#/properties/enabled"
- },
- "locations": {
- "type": "array",
- "minItems": 0,
- "items": {
- "type": "object",
- "required": ["forward_scheme", "forward_host", "forward_port", "path"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "type": ["integer", "null"]
- },
- "path": {
- "type": "string",
- "minLength": 1
- },
- "forward_scheme": {
- "$ref": "#/properties/forward_scheme"
- },
- "forward_host": {
- "$ref": "#/properties/forward_host"
- },
- "forward_port": {
- "$ref": "#/properties/forward_port"
- },
- "forward_path": {
- "type": "string"
- },
- "advanced_config": {
- "type": "string"
- }
- }
- }
- },
- "hsts_enabled": {
- "$ref": "../common.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../common.json#/properties/hsts_subdomains"
- },
- "certificate": {
- "oneOf": [
- {
- "type": "null"
- },
- {
- "$ref": "./certificate-object.json"
- }
- ]
- },
- "owner": {
- "$ref": "./user-object.json"
- },
- "access_list": {
- "oneOf": [
- {
- "type": "null"
- },
- {
- "$ref": "./access-list-object.json"
- }
- ]
- }
- }
-}
diff --git a/backend/schema/components/redirection-host-list.json b/backend/schema/components/redirection-host-list.json
deleted file mode 100644
index 716dcfa1..00000000
--- a/backend/schema/components/redirection-host-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "array",
- "description": "Redirection Hosts list",
- "items": {
- "$ref": "./redirection-host-object.json"
- }
-}
diff --git a/backend/schema/components/redirection-host-object.json b/backend/schema/components/redirection-host-object.json
deleted file mode 100644
index e7a495fd..00000000
--- a/backend/schema/components/redirection-host-object.json
+++ /dev/null
@@ -1,72 +0,0 @@
-{
- "type": "object",
- "description": "Redirection Host object",
- "required": ["id", "created_on", "modified_on", "owner_user_id", "domain_names", "forward_http_code", "forward_scheme", "forward_domain_name", "preserve_path", "certificate_id", "ssl_forced", "hsts_enabled", "hsts_subdomains", "http2_support", "block_exploits", "advanced_config", "enabled", "meta"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "$ref": "../common.json#/properties/id"
- },
- "created_on": {
- "$ref": "../common.json#/properties/created_on"
- },
- "modified_on": {
- "$ref": "../common.json#/properties/modified_on"
- },
- "owner_user_id": {
- "$ref": "../common.json#/properties/user_id"
- },
- "domain_names": {
- "$ref": "../common.json#/properties/domain_names"
- },
- "forward_http_code": {
- "description": "Redirect HTTP Status Code",
- "example": 302,
- "type": "integer",
- "minimum": 300,
- "maximum": 308
- },
- "forward_scheme": {
- "type": "string",
- "enum": ["auto", "http", "https"]
- },
- "forward_domain_name": {
- "description": "Domain Name",
- "example": "jc21.com",
- "type": "string",
- "pattern": "^(?:[^.*]+\\.?)+[^.]$"
- },
- "preserve_path": {
- "description": "Should the path be preserved",
- "example": true,
- "type": "boolean"
- },
- "certificate_id": {
- "$ref": "../common.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../common.json#/properties/ssl_forced"
- },
- "hsts_enabled": {
- "$ref": "../common.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../common.json#/properties/hsts_subdomains"
- },
- "http2_support": {
- "$ref": "../common.json#/properties/http2_support"
- },
- "block_exploits": {
- "$ref": "../common.json#/properties/block_exploits"
- },
- "advanced_config": {
- "type": "string"
- },
- "enabled": {
- "$ref": "../common.json#/properties/enabled"
- },
- "meta": {
- "type": "object"
- }
- }
-}
diff --git a/backend/schema/components/security-schemes.json b/backend/schema/components/security-schemes.json
deleted file mode 100644
index 82407be3..00000000
--- a/backend/schema/components/security-schemes.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "BearerAuth": {
- "type": "http",
- "scheme": "bearer"
- }
-}
diff --git a/backend/schema/components/setting-list.json b/backend/schema/components/setting-list.json
deleted file mode 100644
index c66f099e..00000000
--- a/backend/schema/components/setting-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "array",
- "description": "Setting list",
- "items": {
- "$ref": "./setting-object.json"
- }
-}
diff --git a/backend/schema/components/setting-object.json b/backend/schema/components/setting-object.json
deleted file mode 100644
index b9c6a103..00000000
--- a/backend/schema/components/setting-object.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "type": "object",
- "description": "Setting object",
- "required": ["id", "name", "description", "value", "meta"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "type": "string",
- "description": "Setting ID",
- "minLength": 1,
- "example": "default-site"
- },
- "name": {
- "type": "string",
- "description": "Setting Display Name",
- "minLength": 1,
- "example": "Default Site"
- },
- "description": {
- "type": "string",
- "description": "Meaningful description",
- "minLength": 1,
- "example": "What to show when Nginx is hit with an unknown Host"
- },
- "value": {
- "description": "Value in almost any form",
- "example": "congratulations",
- "anyOf": [
- {
- "type": "string",
- "minLength": 1
- },
- {
- "type": "integer"
- },
- {
- "type": "object"
- },
- {
- "type": "number"
- },
- {
- "type": "array"
- }
- ]
- },
- "meta": {
- "description": "Extra metadata",
- "example": {
- "redirect": "http://example.com",
- "html": "404 "
- },
- "type": "object"
- }
- }
-}
diff --git a/backend/schema/components/stream-list.json b/backend/schema/components/stream-list.json
deleted file mode 100644
index b6e8b6d4..00000000
--- a/backend/schema/components/stream-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "array",
- "description": "Streams list",
- "items": {
- "$ref": "./stream-object.json"
- }
-}
diff --git a/backend/schema/components/stream-object.json b/backend/schema/components/stream-object.json
deleted file mode 100644
index 848c30e6..00000000
--- a/backend/schema/components/stream-object.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "type": "object",
- "description": "Stream object",
- "required": ["id", "created_on", "modified_on", "owner_user_id", "incoming_port", "forwarding_host", "forwarding_port", "tcp_forwarding", "udp_forwarding", "enabled", "meta"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "$ref": "../common.json#/properties/id"
- },
- "created_on": {
- "$ref": "../common.json#/properties/created_on"
- },
- "modified_on": {
- "$ref": "../common.json#/properties/modified_on"
- },
- "owner_user_id": {
- "$ref": "../common.json#/properties/user_id"
- },
- "incoming_port": {
- "type": "integer",
- "minimum": 1,
- "maximum": 65535
- },
- "forwarding_host": {
- "anyOf": [
- {
- "description": "Domain Name",
- "example": "jc21.com",
- "type": "string",
- "pattern": "^(?:[^.*]+\\.?)+[^.]$"
- },
- {
- "type": "string",
- "format": "ipv4"
- },
- {
- "type": "string",
- "format": "ipv6"
- }
- ]
- },
- "forwarding_port": {
- "type": "integer",
- "minimum": 1,
- "maximum": 65535
- },
- "tcp_forwarding": {
- "type": "boolean"
- },
- "udp_forwarding": {
- "type": "boolean"
- },
- "enabled": {
- "$ref": "../common.json#/properties/enabled"
- },
- "certificate_id": {
- "$ref": "../common.json#/properties/certificate_id"
- },
- "meta": {
- "type": "object"
- },
- "owner": {
- "$ref": "./user-object.json"
- },
- "certificate": {
- "oneOf": [
- {
- "type": "null"
- },
- {
- "$ref": "./certificate-object.json"
- }
- ]
- }
- }
-}
diff --git a/backend/schema/components/token-object.json b/backend/schema/components/token-object.json
deleted file mode 100644
index 6ec4e434..00000000
--- a/backend/schema/components/token-object.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "type": "object",
- "description": "Token object",
- "required": ["expires", "token"],
- "additionalProperties": false,
- "properties": {
- "expires": {
- "description": "Token Expiry ISO Time String",
- "example": "2025-02-04T20:40:46.340Z",
- "type": "string"
- },
- "token": {
- "description": "JWT Token",
- "example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4",
- "type": "string"
- }
- }
-}
diff --git a/backend/schema/components/user-list.json b/backend/schema/components/user-list.json
deleted file mode 100644
index c5c0f711..00000000
--- a/backend/schema/components/user-list.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "array",
- "description": "User list",
- "items": {
- "$ref": "./user-object.json"
- }
-}
diff --git a/backend/schema/components/user-object.json b/backend/schema/components/user-object.json
deleted file mode 100644
index 180e8f19..00000000
--- a/backend/schema/components/user-object.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "type": "object",
- "description": "User object",
- "required": ["id", "created_on", "modified_on", "is_disabled", "email", "name", "nickname", "avatar", "roles"],
- "additionalProperties": false,
- "properties": {
- "id": {
- "type": "integer",
- "description": "User ID",
- "minimum": 1,
- "example": 1
- },
- "created_on": {
- "type": "string",
- "description": "Created Date",
- "example": "2020-01-30T09:36:08.000Z"
- },
- "modified_on": {
- "type": "string",
- "description": "Modified Date",
- "example": "2020-01-30T09:41:04.000Z"
- },
- "is_disabled": {
- "type": "boolean",
- "description": "Is user Disabled",
- "example": true
- },
- "email": {
- "type": "string",
- "description": "Email",
- "minLength": 3,
- "example": "jc@jc21.com"
- },
- "name": {
- "type": "string",
- "description": "Name",
- "minLength": 1,
- "example": "Jamie Curnow"
- },
- "nickname": {
- "type": "string",
- "description": "Nickname",
- "example": "James"
- },
- "avatar": {
- "type": "string",
- "description": "Gravatar URL based on email, without scheme",
- "example": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm"
- },
- "roles": {
- "description": "Roles applied",
- "example": ["admin"],
- "type": "array",
- "items": {
- "type": "string"
- }
- }
- }
-}
diff --git a/backend/schema/index.js b/backend/schema/index.js
deleted file mode 100644
index 87b75f25..00000000
--- a/backend/schema/index.js
+++ /dev/null
@@ -1,41 +0,0 @@
-const refParser = require('@apidevtools/json-schema-ref-parser');
-
-let compiledSchema = null;
-
-module.exports = {
-
- /**
- * Compiles the schema, by dereferencing it, only once
- * and returns the memory cached value
- */
- getCompiledSchema: async () => {
- if (compiledSchema === null) {
- compiledSchema = await refParser.dereference(__dirname + '/swagger.json', {
- mutateInputSchema: false,
- });
- }
- return compiledSchema;
- },
-
- /**
- * Scans the schema for the validation schema for the given path and method
- * and returns it.
- *
- * @param {string} path
- * @param {string} method
- * @returns string|null
- */
- getValidationSchema: (path, method) => {
- if (compiledSchema !== null &&
- typeof compiledSchema.paths[path] !== 'undefined' &&
- typeof compiledSchema.paths[path][method] !== 'undefined' &&
- typeof compiledSchema.paths[path][method].requestBody !== 'undefined' &&
- typeof compiledSchema.paths[path][method].requestBody.content !== 'undefined' &&
- typeof compiledSchema.paths[path][method].requestBody.content['application/json'] !== 'undefined' &&
- typeof compiledSchema.paths[path][method].requestBody.content['application/json'].schema !== 'undefined'
- ) {
- return compiledSchema.paths[path][method].requestBody.content['application/json'].schema;
- }
- return null;
- }
-};
diff --git a/backend/schema/paths/audit-log/get.json b/backend/schema/paths/audit-log/get.json
deleted file mode 100644
index bc43e29d..00000000
--- a/backend/schema/paths/audit-log/get.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "operationId": "getAuditLog",
- "summary": "Get Audit Log",
- "tags": ["Audit Log"],
- "security": [
- {
- "BearerAuth": ["audit-log"]
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": 7,
- "created_on": "2024-10-08T13:09:54.000Z",
- "modified_on": "2024-10-08T13:09:54.000Z",
- "user_id": 1,
- "object_type": "user",
- "object_id": 3,
- "action": "updated",
- "meta": {
- "name": "John Doe",
- "permissions": {
- "user_id": 3,
- "visibility": "all",
- "access_lists": "manage",
- "dead_hosts": "hidden",
- "proxy_hosts": "manage",
- "redirection_hosts": "view",
- "streams": "hidden",
- "certificates": "manage",
- "id": 3,
- "modified_on": "2024-10-08T13:09:54.000Z",
- "created_on": "2024-10-08T13:09:51.000Z"
- }
- }
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../components/audit-log-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/get.json b/backend/schema/paths/get.json
deleted file mode 100644
index 8c3a4e02..00000000
--- a/backend/schema/paths/get.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
- "operationId": "health",
- "summary": "Returns the API health status",
- "tags": ["Public"],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "status": "OK",
- "version": {
- "major": 2,
- "minor": 1,
- "revision": 0
- }
- }
- }
- },
- "schema": {
- "$ref": "../components/health-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/access-lists/get.json b/backend/schema/paths/nginx/access-lists/get.json
deleted file mode 100644
index a8b9adc6..00000000
--- a/backend/schema/paths/nginx/access-lists/get.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "operationId": "getAccessLists",
- "summary": "Get all access lists",
- "tags": ["Access Lists"],
- "security": [
- {
- "BearerAuth": ["access_lists"]
- }
- ],
- "parameters": [
- {
- "in": "query",
- "name": "expand",
- "description": "Expansions",
- "schema": {
- "type": "string",
- "enum": ["owner", "items", "clients", "proxy_hosts"]
- }
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": 1,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:15:40.000Z",
- "owner_user_id": 1,
- "name": "test1234",
- "meta": {},
- "satisfy_any": true,
- "pass_auth": false,
- "proxy_host_count": 0
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../../components/access-list-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/access-lists/listID/delete.json b/backend/schema/paths/nginx/access-lists/listID/delete.json
deleted file mode 100644
index 073585c8..00000000
--- a/backend/schema/paths/nginx/access-lists/listID/delete.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "operationId": "deleteAccessList",
- "summary": "Delete a Access List",
- "tags": ["Access Lists"],
- "security": [
- {
- "BearerAuth": ["access_lists"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "listID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/access-lists/listID/get.json b/backend/schema/paths/nginx/access-lists/listID/get.json
deleted file mode 100644
index e67023f8..00000000
--- a/backend/schema/paths/nginx/access-lists/listID/get.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "operationId": "getAccessList",
- "summary": "Get a access List",
- "tags": ["Access Lists"],
- "security": [
- {
- "BearerAuth": ["access_lists"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "listID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 1
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2020-01-30T09:36:08.000Z",
- "modified_on": "2020-01-30T09:41:04.000Z",
- "is_disabled": false,
- "email": "jc@jc21.com",
- "name": "Jamie Curnow",
- "nickname": "James",
- "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
- "roles": ["admin"]
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/access-list-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/access-lists/listID/put.json b/backend/schema/paths/nginx/access-lists/listID/put.json
deleted file mode 100644
index 7f887dad..00000000
--- a/backend/schema/paths/nginx/access-lists/listID/put.json
+++ /dev/null
@@ -1,163 +0,0 @@
-{
- "operationId": "updateAccessList",
- "summary": "Update a Access List",
- "tags": ["Access Lists"],
- "security": [
- {
- "BearerAuth": ["access_lists"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "listID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "requestBody": {
- "description": "Access List Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "name": {
- "$ref": "../../../../components/access-list-object.json#/properties/name"
- },
- "satisfy_any": {
- "$ref": "../../../../components/access-list-object.json#/properties/satisfy_any"
- },
- "pass_auth": {
- "$ref": "../../../../components/access-list-object.json#/properties/pass_auth"
- },
- "items": {
- "type": "array",
- "items": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "username": {
- "type": "string",
- "minLength": 1
- },
- "password": {
- "type": "string"
- }
- }
- }
- },
- "clients": {
- "type": "array",
- "items": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "address": {
- "oneOf": [
- {
- "type": "string",
- "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$"
- },
- {
- "type": "string",
- "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"
- },
- {
- "type": "string",
- "pattern": "^all$"
- }
- ]
- },
- "directive": {
- "$ref": "../../../../components/access-list-object.json#/properties/directive"
- }
- }
- }
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:34:34.000Z",
- "owner_user_id": 1,
- "name": "test123!!",
- "meta": {},
- "satisfy_any": true,
- "pass_auth": false,
- "proxy_host_count": 0,
- "owner": {
- "id": 1,
- "created_on": "2024-10-07T22:43:55.000Z",
- "modified_on": "2024-10-08T12:52:54.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "some guy",
- "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
- "roles": ["admin"]
- },
- "items": [
- {
- "id": 1,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:15:40.000Z",
- "access_list_id": 1,
- "username": "admin",
- "password": "",
- "meta": {},
- "hint": "a****"
- },
- {
- "id": 2,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:15:40.000Z",
- "access_list_id": 1,
- "username": "asdad",
- "password": "",
- "meta": {},
- "hint": "a*****"
- }
- ],
- "clients": [
- {
- "id": 1,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:15:40.000Z",
- "access_list_id": 1,
- "address": "127.0.0.1",
- "directive": "allow",
- "meta": {}
- }
- ],
- "proxy_hosts": []
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/access-list-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/access-lists/post.json b/backend/schema/paths/nginx/access-lists/post.json
deleted file mode 100644
index 4c5a4edd..00000000
--- a/backend/schema/paths/nginx/access-lists/post.json
+++ /dev/null
@@ -1,155 +0,0 @@
-{
- "operationId": "createAccessList",
- "summary": "Create a Access List",
- "tags": ["Access Lists"],
- "security": [
- {
- "BearerAuth": ["access_lists"]
- }
- ],
- "requestBody": {
- "description": "Access List Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["name"],
- "properties": {
- "name": {
- "$ref": "../../../components/access-list-object.json#/properties/name"
- },
- "satisfy_any": {
- "$ref": "../../../components/access-list-object.json#/properties/satisfy_any"
- },
- "pass_auth": {
- "$ref": "../../../components/access-list-object.json#/properties/pass_auth"
- },
- "items": {
- "type": "array",
- "items": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "username": {
- "type": "string",
- "minLength": 1
- },
- "password": {
- "type": "string",
- "minLength": 1
- }
- }
- }
- },
- "clients": {
- "type": "array",
- "items": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "address": {
- "oneOf": [
- {
- "type": "string",
- "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}(/([0-9]|[1-2][0-9]|3[0-2]))?$"
- },
- {
- "type": "string",
- "pattern": "^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$"
- },
- {
- "type": "string",
- "pattern": "^all$"
- }
- ]
- },
- "directive": {
- "$ref": "../../../components/access-list-object.json#/properties/directive"
- }
- }
- }
- },
- "meta": {
- "$ref": "../../../components/access-list-object.json#/properties/meta"
- }
- }
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "201 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:15:40.000Z",
- "owner_user_id": 1,
- "name": "test1234",
- "meta": {},
- "satisfy_any": true,
- "pass_auth": false,
- "proxy_host_count": 0,
- "owner": {
- "id": 1,
- "created_on": "2024-10-07T22:43:55.000Z",
- "modified_on": "2024-10-08T12:52:54.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "some guy",
- "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
- "roles": ["admin"]
- },
- "items": [
- {
- "id": 1,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:15:40.000Z",
- "access_list_id": 1,
- "username": "admin",
- "password": "",
- "meta": {},
- "hint": "a****"
- },
- {
- "id": 2,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:15:40.000Z",
- "access_list_id": 1,
- "username": "asdad",
- "password": "",
- "meta": {},
- "hint": "a*****"
- }
- ],
- "proxy_hosts": [],
- "clients": [
- {
- "id": 1,
- "created_on": "2024-10-08T22:15:40.000Z",
- "modified_on": "2024-10-08T22:15:40.000Z",
- "access_list_id": 1,
- "address": "127.0.0.1",
- "directive": "allow",
- "meta": {}
- }
- ]
- }
- }
- },
- "schema": {
- "$ref": "../../../components/access-list-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/certID/delete.json b/backend/schema/paths/nginx/certificates/certID/delete.json
deleted file mode 100644
index 0d40bcb8..00000000
--- a/backend/schema/paths/nginx/certificates/certID/delete.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "operationId": "deleteCertificate",
- "summary": "Delete a Certificate",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "certID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/certID/download/get.json b/backend/schema/paths/nginx/certificates/certID/download/get.json
deleted file mode 100644
index 4b858cae..00000000
--- a/backend/schema/paths/nginx/certificates/certID/download/get.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "operationId": "downloadCertificate",
- "summary": "Downloads a Certificate",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "certID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 1
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/zip": {
- "schema": {
- "type": "string",
- "format": "binary"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/certID/get.json b/backend/schema/paths/nginx/certificates/certID/get.json
deleted file mode 100644
index 22317b33..00000000
--- a/backend/schema/paths/nginx/certificates/certID/get.json
+++ /dev/null
@@ -1,53 +0,0 @@
-{
- "operationId": "getCertificate",
- "summary": "Get a Certificate",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "certID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 1
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 4,
- "created_on": "2024-10-09T05:31:58.000Z",
- "modified_on": "2024-10-09T05:32:11.000Z",
- "owner_user_id": 1,
- "provider": "letsencrypt",
- "nice_name": "test.example.com",
- "domain_names": ["test.example.com"],
- "expires_on": "2025-01-07T04:34:18.000Z",
- "meta": {
- "letsencrypt_email": "jc@jc21.com",
- "letsencrypt_agree": true,
- "dns_challenge": false
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/certificate-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/certID/renew/post.json b/backend/schema/paths/nginx/certificates/certID/renew/post.json
deleted file mode 100644
index ef4d20e5..00000000
--- a/backend/schema/paths/nginx/certificates/certID/renew/post.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "operationId": "renewCertificate",
- "summary": "Renews a Certificate",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "certID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 1
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "expires_on": "2025-01-07T06:41:58.000Z",
- "modified_on": "2024-10-09T07:39:51.000Z",
- "id": 4,
- "created_on": "2024-10-09T05:31:58.000Z",
- "owner_user_id": 1,
- "is_deleted": false,
- "provider": "letsencrypt",
- "nice_name": "My Test Cert",
- "domain_names": ["test.jc21.supernerd.pro"],
- "meta": {
- "letsencrypt_email": "jc@jc21.com",
- "letsencrypt_agree": true,
- "dns_challenge": false
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/certificate-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/certID/upload/post.json b/backend/schema/paths/nginx/certificates/certID/upload/post.json
deleted file mode 100644
index f38b8102..00000000
--- a/backend/schema/paths/nginx/certificates/certID/upload/post.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
- "operationId": "uploadCertificate",
- "summary": "Uploads a custom Certificate",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "certID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 1
- }
- ],
- "requestBody": {
- "description": "Certificate Files",
- "required": true,
- "content": {
- "multipart/form-data": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["certificate", "certificate_key"],
- "properties": {
- "certificate": {
- "type": "string"
- },
- "certificate_key": {
- "type": "string"
- },
- "intermediate_certificate": {
- "type": "string"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "certificate": "-----BEGIN CERTIFICATE-----\nMIIEYDCCAsigAwIBAgIRAPoSC0hvitb26ODMlsH6YbowDQYJKoZIhvcNAQELBQAw\ngZExHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTEzMDEGA1UECwwqamN1\ncm5vd0BKYW1pZXMtTGFwdG9wLmxvY2FsIChKYW1pZSBDdXJub3cpMTowOAYDVQQD\nDDFta2NlcnQgamN1cm5vd0BKYW1pZXMtTGFwdG9wLmxvY2FsIChKYW1pZSBDdXJu\nb3cpMB4XDTI0MTAwOTA3MjIxN1oXDTI3MDEwOTA3MjIxN1owXjEnMCUGA1UEChMe\nbWtjZXJ0IGRldmVsb3BtZW50IGNlcnRpZmljYXRlMTMwMQYDVQQLDCpqY3Vybm93\nQEphbWllcy1MYXB0b3AubG9jYWwgKEphbWllIEN1cm5vdykwggEiMA0GCSqGSIb3\nDQEBAQUAA4IBDwAwggEKAoIBAQC1n9j9C5Bes1ndqACDckERauxXVNKCnUlUM1bu\nGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2wrbmvZvLuPmXePOKbIKS+XXh+\n2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHgeYz6Cv/Si2/LJPCh/CoBfM4hU\nQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQoxRAHiOR9081Xn1WeoKr7kVB\nIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7ZEo+nS8Wr/4QWicatIWZXpVaE\nOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79XzGONeH1PAgMBAAGjZTBjMA4G\nA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBSB\n/vfmBUd4W7CvyEMl7YpMVQs8vTAbBgNVHREEFDASghB0ZXN0LmV4YW1wbGUuY29t\nMA0GCSqGSIb3DQEBCwUAA4IBgQASwON/jPAHzcARSenY0ZGY1m5OVTYoQ/JWH0oy\nl8SyFCQFEXt7UHDD/eTtLT0vMyc190nP57P8lTnZGf7hSinZz1B1d6V4cmzxpk0s\nVXZT+irL6bJVJoMBHRpllKAhGULIo33baTrWFKA0oBuWx4AevSWKcLW5j87kEawn\nATCuMQ1I3ifR1mSlB7X8fb+vF+571q0NGuB3a42j6rdtXJ6SmH4+9B4qO0sfHDNt\nIImpLCH/tycDpcYrGSCn1QrekFG1bSEh+Bb9i8rqMDSDsYrTFPZTuOQ3EtjGni9u\nm+rEP3OyJg+md8c+0LVP7/UU4QWWnw3/Wolo5kSCxE8vNTFqi4GhVbdLnUtcIdTV\nXxuR6cKyW87Snj1a0nG76ZLclt/akxDhtzqeV60BO0p8pmiev8frp+E94wFNYCmp\n1cr3CnMEGRaficLSDFC6EBENzlZW2BQT6OMIV+g0NBgSyQe39s2zcdEl5+SzDVuw\nhp8bJUp/QN7pnOVCDbjTQ+HVMXw=\n-----END CERTIFICATE-----\n",
- "certificate_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1n9j9C5Bes1nd\nqACDckERauxXVNKCnUlUM1buGBx1xc+j2e2Ar23wUJJuWBY18VfT8yqfqVDktO2w\nrbmvZvLuPmXePOKbIKS+XXh+2NG9L5bDG9rwGFCRXnbQj+GWCdMfzx14+CR1IHge\nYz6Cv/Si2/LJPCh/CoBfM4hUQJON3lxAWrWBpdbZnKYMrxuPBRfW9OuzTbCVXToQ\noxRAHiOR9081Xn1WeoKr7kVBIa5UphlvWXa12w1YmUwJu7YndnJGIavLWeNCVc7Z\nEo+nS8Wr/4QWicatIWZXpVaEOPhRoeplQDxNWg5b/Q26rYoVd7PrCmRs7sVcH79X\nzGONeH1PAgMBAAECggEAANb3Wtwl07pCjRrMvc7WbC0xYIn82yu8/g2qtjkYUJcU\nia5lQbYN7RGCS85Oc/tkq48xQEG5JQWNH8b918jDEMTrFab0aUEyYcru1q9L8PL6\nYHaNgZSrMrDcHcS8h0QOXNRJT5jeGkiHJaTR0irvB526tqF3knbK9yW22KTfycUe\na0Z9voKn5xRk1DCbHi/nk2EpT7xnjeQeLFaTIRXbS68omkr4YGhwWm5OizoyEGZu\nW0Zum5BkQyMr6kor3wdxOTG97ske2rcyvvHi+ErnwL0xBv0qY0Dhe8DpuXpDezqw\no72yY8h31Fu84i7sAj24YuE5Df8DozItFXQpkgbQ6QKBgQDPrufhvIFm2S/MzBdW\nH8JxY7CJlJPyxOvc1NIl9RczQGAQR90kx52cgIcuIGEG6/wJ/xnGfMmW40F0DnQ+\nN+oLgB9SFxeLkRb7s9Z/8N3uIN8JJFYcerEOiRQeN2BXEEWJ7bUThNtsVrAcKoUh\nELsDmnHW/3V+GKwhd0vpk842+wKBgQDf4PGLG9PTE5tlAoyHFodJRd2RhTJQkwsU\nMDNjLJ+KecLv+Nl+QiJhoflG1ccqtSFlBSCG067CDQ5LV0xm3mLJ7pfJoMgjcq31\nqjEmX4Ls91GuVOPtbwst3yFKjsHaSoKB5fBvWRcKFpBUezM7Qcw2JP3+dQT+bQIq\ncMTkRWDSvQKBgQDOdCQFDjxg/lR7NQOZ1PaZe61aBz5P3pxNqa7ClvMaOsuEQ7w9\nvMYcdtRq8TsjA2JImbSI0TIg8gb2FQxPcYwTJKl+FICOeIwtaSg5hTtJZpnxX5LO\nutTaC0DZjNkTk5RdOdWA8tihyUdGqKoxJY2TVmwGe2rUEDjFB++J4inkEwKBgB6V\ng0nmtkxanFrzOzFlMXwgEEHF+Xaqb9QFNa/xs6XeNnREAapO7JV75Cr6H2hFMFe1\nmJjyqCgYUoCWX3iaHtLJRnEkBtNY4kzyQB6m46LtsnnnXO/dwKA2oDyoPfFNRoDq\nYatEd3JIXNU9s2T/+x7WdOBjKhh72dTkbPFmTPDdAoGAU6rlPBevqOFdObYxdPq8\nEQWu44xqky3Mf5sBpOwtu6rqCYuziLiN7K4sjN5GD5mb1cEU+oS92ZiNcUQ7MFXk\n8yTYZ7U0VcXyAcpYreWwE8thmb0BohJBr+Mp3wLTx32x0HKdO6vpUa0d35LUTUmM\nRrKmPK/msHKK/sVHiL+NFqo=\n-----END PRIVATE KEY-----\n"
- }
- }
- },
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["certificate", "certificate_key"],
- "properties": {
- "certificate": {
- "type": "string",
- "minLength": 1
- },
- "certificate_key": {
- "type": "string",
- "minLength": 1
- },
- "intermediate_certificate": {
- "type": "string",
- "minLength": 1
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/get.json b/backend/schema/paths/nginx/certificates/get.json
deleted file mode 100644
index 2f4b556a..00000000
--- a/backend/schema/paths/nginx/certificates/get.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "operationId": "getCertificates",
- "summary": "Get all certificates",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "parameters": [
- {
- "in": "query",
- "name": "expand",
- "description": "Expansions",
- "schema": {
- "type": "string",
- "enum": ["owner"]
- }
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": 4,
- "created_on": "2024-10-09T05:31:58.000Z",
- "modified_on": "2024-10-09T05:32:11.000Z",
- "owner_user_id": 1,
- "provider": "letsencrypt",
- "nice_name": "test.example.com",
- "domain_names": ["test.example.com"],
- "expires_on": "2025-01-07T04:34:18.000Z",
- "meta": {
- "letsencrypt_email": "jc@jc21.com",
- "letsencrypt_agree": true,
- "dns_challenge": false
- }
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../../components/certificate-list.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/post.json b/backend/schema/paths/nginx/certificates/post.json
deleted file mode 100644
index 5a3306c2..00000000
--- a/backend/schema/paths/nginx/certificates/post.json
+++ /dev/null
@@ -1,97 +0,0 @@
-{
- "operationId": "createCertificate",
- "summary": "Create a Certificate",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "requestBody": {
- "description": "Certificate Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["provider"],
- "properties": {
- "provider": {
- "$ref": "../../../components/certificate-object.json#/properties/provider"
- },
- "nice_name": {
- "$ref": "../../../components/certificate-object.json#/properties/nice_name"
- },
- "domain_names": {
- "$ref": "../../../components/certificate-object.json#/properties/domain_names"
- },
- "meta": {
- "$ref": "../../../components/certificate-object.json#/properties/meta"
- }
- }
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "201 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "expires_on": "2025-01-07 04:30:17",
- "modified_on": "2024-10-09 05:28:51",
- "id": 5,
- "created_on": "2024-10-09 05:28:35",
- "owner_user_id": 1,
- "is_deleted": false,
- "provider": "letsencrypt",
- "nice_name": "test.example.com",
- "domain_names": ["test.example.com"],
- "meta": {
- "letsencrypt_email": "jc@jc21.com",
- "letsencrypt_agree": true,
- "dns_challenge": false,
- "letsencrypt_certificate": {
- "cn": "test.example.com",
- "issuer": "C = US, O = Let's Encrypt, CN = E5",
- "dates": {
- "from": 1728448218,
- "to": 1736224217
- }
- }
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../components/certificate-object.json"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Domains are invalid"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/test-http/get.json b/backend/schema/paths/nginx/certificates/test-http/get.json
deleted file mode 100644
index 2b9a8dd3..00000000
--- a/backend/schema/paths/nginx/certificates/test-http/get.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "operationId": "testHttpReach",
- "summary": "Test HTTP Reachability",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "parameters": [
- {
- "in": "query",
- "name": "domains",
- "description": "Expansions",
- "required": true,
- "schema": {
- "type": "string",
- "example": "[\"test.example.ord\",\"test.example.com\",\"nonexistent.example.com\"]"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "test.example.org": "ok",
- "test.example.com": "other:Invalid domain or IP",
- "nonexistent.example.com": "404"
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/certificates/validate/post.json b/backend/schema/paths/nginx/certificates/validate/post.json
deleted file mode 100644
index 21eb325e..00000000
--- a/backend/schema/paths/nginx/certificates/validate/post.json
+++ /dev/null
@@ -1,114 +0,0 @@
-{
- "operationId": "validateCertificates",
- "summary": "Validates given Custom Certificates",
- "tags": ["Certificates"],
- "security": [
- {
- "BearerAuth": ["certificates"]
- }
- ],
- "requestBody": {
- "description": "Certificate Files",
- "required": true,
- "content": {
- "multipart/form-data": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["certificate", "certificate_key"],
- "properties": {
- "certificate": {
- "type": "string"
- },
- "certificate_key": {
- "type": "string"
- },
- "intermediate_certificate": {
- "type": "string"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "certificate": {
- "cn": "mkcert",
- "issuer": "O = mkcert development CA, OU = jc@jc-Laptop.local (John Doe), CN = mkcert jc@jc-Laptop.local (John Doe)",
- "dates": {
- "from": 1728458537,
- "to": 1799479337
- }
- },
- "certificate_key": true
- }
- }
- },
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["certificate", "certificate_key"],
- "properties": {
- "certificate": {
- "type": "object",
- "additionalProperties": false,
- "required": ["cn", "issuer", "dates"],
- "properties": {
- "cn": {
- "type": "string"
- },
- "issuer": {
- "type": "string"
- },
- "dates": {
- "type": "object",
- "additionalProperties": false,
- "required": ["from", "to"],
- "properties": {
- "from": {
- "type": "integer"
- },
- "to": {
- "type": "integer"
- }
- }
- }
- }
- },
- "certificate_key": {
- "type": "boolean"
- }
- }
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Certificate is not valid"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/dead-hosts/get.json b/backend/schema/paths/nginx/dead-hosts/get.json
deleted file mode 100644
index 8a11a3f6..00000000
--- a/backend/schema/paths/nginx/dead-hosts/get.json
+++ /dev/null
@@ -1,57 +0,0 @@
-{
- "operationId": "getDeadHosts",
- "summary": "Get all 404 hosts",
- "tags": ["404 Hosts"],
- "security": [
- {
- "BearerAuth": ["dead_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "query",
- "name": "expand",
- "description": "Expansions",
- "schema": {
- "type": "string",
- "enum": ["owner", "certificate"]
- }
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": 1,
- "created_on": "2024-10-09T01:38:52.000Z",
- "modified_on": "2024-10-09T01:38:52.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "certificate_id": 0,
- "ssl_forced": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "http2_support": false,
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../../components/dead-host-list.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/delete.json b/backend/schema/paths/nginx/dead-hosts/hostID/delete.json
deleted file mode 100644
index f3aa81a5..00000000
--- a/backend/schema/paths/nginx/dead-hosts/hostID/delete.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "operationId": "deleteDeadHost",
- "summary": "Delete a 404 Host",
- "tags": ["404 Hosts"],
- "security": [
- {
- "BearerAuth": ["dead_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json
deleted file mode 100644
index 2cdcecf4..00000000
--- a/backend/schema/paths/nginx/dead-hosts/hostID/disable/post.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "operationId": "disableDeadHost",
- "summary": "Disable a 404 Host",
- "tags": ["404 Hosts"],
- "security": [
- {
- "BearerAuth": ["dead_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Host is already disabled"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json
deleted file mode 100644
index ca3ce9fa..00000000
--- a/backend/schema/paths/nginx/dead-hosts/hostID/enable/post.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "operationId": "enableDeadHost",
- "summary": "Enable a 404 Host",
- "tags": ["404 Hosts"],
- "security": [
- {
- "BearerAuth": ["dead_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Host is already enabled"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/get.json b/backend/schema/paths/nginx/dead-hosts/hostID/get.json
deleted file mode 100644
index 47e2f8b1..00000000
--- a/backend/schema/paths/nginx/dead-hosts/hostID/get.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "operationId": "getDeadHost",
- "summary": "Get a 404 Host",
- "tags": ["404 Hosts"],
- "security": [
- {
- "BearerAuth": ["dead_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 1
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T01:38:52.000Z",
- "modified_on": "2024-10-09T01:38:52.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "certificate_id": 0,
- "ssl_forced": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "http2_support": false,
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/dead-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/dead-hosts/hostID/put.json b/backend/schema/paths/nginx/dead-hosts/hostID/put.json
deleted file mode 100644
index f9505ed4..00000000
--- a/backend/schema/paths/nginx/dead-hosts/hostID/put.json
+++ /dev/null
@@ -1,108 +0,0 @@
-{
- "operationId": "updateDeadHost",
- "summary": "Update a 404 Host",
- "tags": ["404 Hosts"],
- "security": [
- {
- "BearerAuth": ["dead_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "requestBody": {
- "description": "404 Host Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "domain_names": {
- "$ref": "../../../../components/dead-host-object.json#/properties/domain_names"
- },
- "certificate_id": {
- "$ref": "../../../../components/dead-host-object.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../../../../components/dead-host-object.json#/properties/ssl_forced"
- },
- "hsts_enabled": {
- "$ref": "../../../../components/dead-host-object.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../../../../components/dead-host-object.json#/properties/hsts_subdomains"
- },
- "http2_support": {
- "$ref": "../../../../components/dead-host-object.json#/properties/http2_support"
- },
- "advanced_config": {
- "$ref": "../../../../components/dead-host-object.json#/properties/advanced_config"
- },
- "meta": {
- "$ref": "../../../../components/dead-host-object.json#/properties/meta"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T01:38:52.000Z",
- "modified_on": "2024-10-09T01:46:06.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "certificate_id": 0,
- "ssl_forced": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "http2_support": false,
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false,
- "owner": {
- "id": 1,
- "created_on": "2024-10-09T00:59:56.000Z",
- "modified_on": "2024-10-09T00:59:56.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "Admin",
- "avatar": "",
- "roles": ["admin"]
- },
- "certificate": null
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/dead-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/dead-hosts/post.json b/backend/schema/paths/nginx/dead-hosts/post.json
deleted file mode 100644
index c8bbb693..00000000
--- a/backend/schema/paths/nginx/dead-hosts/post.json
+++ /dev/null
@@ -1,93 +0,0 @@
-{
- "operationId": "create404Host",
- "summary": "Create a 404 Host",
- "tags": ["404 Hosts"],
- "security": [
- {
- "BearerAuth": ["dead_hosts"]
- }
- ],
- "requestBody": {
- "description": "404 Host Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["domain_names"],
- "properties": {
- "domain_names": {
- "$ref": "../../../components/dead-host-object.json#/properties/domain_names"
- },
- "certificate_id": {
- "$ref": "../../../components/dead-host-object.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../../../components/dead-host-object.json#/properties/ssl_forced"
- },
- "hsts_enabled": {
- "$ref": "../../../components/dead-host-object.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../../../components/dead-host-object.json#/properties/hsts_subdomains"
- },
- "http2_support": {
- "$ref": "../../../components/dead-host-object.json#/properties/http2_support"
- },
- "advanced_config": {
- "$ref": "../../../components/dead-host-object.json#/properties/advanced_config"
- },
- "meta": {
- "$ref": "../../../components/dead-host-object.json#/properties/meta"
- }
- }
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "201 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T01:38:52.000Z",
- "modified_on": "2024-10-09T01:38:52.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "certificate_id": 0,
- "ssl_forced": false,
- "advanced_config": "",
- "meta": {},
- "http2_support": false,
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false,
- "certificate": null,
- "owner": {
- "id": 1,
- "created_on": "2024-10-09T00:59:56.000Z",
- "modified_on": "2024-10-09T00:59:56.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "Admin",
- "avatar": "",
- "roles": ["admin"]
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../components/dead-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/proxy-hosts/get.json b/backend/schema/paths/nginx/proxy-hosts/get.json
deleted file mode 100644
index 1d9f6335..00000000
--- a/backend/schema/paths/nginx/proxy-hosts/get.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "operationId": "getProxyHosts",
- "summary": "Get all proxy hosts",
- "tags": ["Proxy Hosts"],
- "security": [
- {
- "BearerAuth": ["proxy_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "query",
- "name": "expand",
- "description": "Expansions",
- "schema": {
- "type": "string",
- "enum": ["access_list", "owner", "certificate"]
- }
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": 1,
- "created_on": "2024-10-08T23:23:03.000Z",
- "modified_on": "2024-10-08T23:23:04.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "forward_host": "127.0.0.1",
- "forward_port": 8989,
- "access_list_id": 0,
- "certificate_id": 0,
- "ssl_forced": false,
- "caching_enabled": false,
- "block_exploits": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "allow_websocket_upgrade": false,
- "http2_support": false,
- "forward_scheme": "http",
- "enabled": true,
- "locations": null,
- "hsts_enabled": false,
- "hsts_subdomains": false
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../../components/proxy-host-list.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/delete.json b/backend/schema/paths/nginx/proxy-hosts/hostID/delete.json
deleted file mode 100644
index 991ef0e9..00000000
--- a/backend/schema/paths/nginx/proxy-hosts/hostID/delete.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "operationId": "deleteProxyHost",
- "summary": "Delete a Proxy Host",
- "tags": ["Proxy Hosts"],
- "security": [
- {
- "BearerAuth": ["proxy_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json
deleted file mode 100644
index 54ff8a66..00000000
--- a/backend/schema/paths/nginx/proxy-hosts/hostID/disable/post.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "operationId": "disableProxyHost",
- "summary": "Disable a Proxy Host",
- "tags": ["Proxy Hosts"],
- "security": [
- {
- "BearerAuth": ["proxy_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Host is already disabled"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json
deleted file mode 100644
index 9f052de0..00000000
--- a/backend/schema/paths/nginx/proxy-hosts/hostID/enable/post.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "operationId": "enableProxyHost",
- "summary": "Enable a Proxy Host",
- "tags": ["Proxy Hosts"],
- "security": [
- {
- "BearerAuth": ["proxy_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Host is already enabled"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json b/backend/schema/paths/nginx/proxy-hosts/hostID/get.json
deleted file mode 100644
index 5e10a9cf..00000000
--- a/backend/schema/paths/nginx/proxy-hosts/hostID/get.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
- "operationId": "getProxyHost",
- "summary": "Get a Proxy Host",
- "tags": ["Proxy Hosts"],
- "security": [
- {
- "BearerAuth": ["proxy_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 1
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-08T23:23:03.000Z",
- "modified_on": "2024-10-08T23:26:38.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "forward_host": "192.168.0.10",
- "forward_port": 8989,
- "access_list_id": 0,
- "certificate_id": 0,
- "ssl_forced": false,
- "caching_enabled": false,
- "block_exploits": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "allow_websocket_upgrade": false,
- "http2_support": false,
- "forward_scheme": "http",
- "enabled": true,
- "locations": null,
- "hsts_enabled": false,
- "hsts_subdomains": false
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/proxy-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json b/backend/schema/paths/nginx/proxy-hosts/hostID/put.json
deleted file mode 100644
index 5cab6e75..00000000
--- a/backend/schema/paths/nginx/proxy-hosts/hostID/put.json
+++ /dev/null
@@ -1,143 +0,0 @@
-{
- "operationId": "updateProxyHost",
- "summary": "Update a Proxy Host",
- "tags": ["Proxy Hosts"],
- "security": [
- {
- "BearerAuth": ["proxy_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "requestBody": {
- "description": "Proxy Host Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "domain_names": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/domain_names"
- },
- "forward_scheme": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/forward_scheme"
- },
- "forward_host": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/forward_host"
- },
- "forward_port": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/forward_port"
- },
- "certificate_id": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/ssl_forced"
- },
- "hsts_enabled": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/hsts_subdomains"
- },
- "http2_support": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/http2_support"
- },
- "block_exploits": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/block_exploits"
- },
- "caching_enabled": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/caching_enabled"
- },
- "allow_websocket_upgrade": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/allow_websocket_upgrade"
- },
- "access_list_id": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/access_list_id"
- },
- "advanced_config": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/advanced_config"
- },
- "enabled": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/enabled"
- },
- "meta": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/meta"
- },
- "locations": {
- "$ref": "../../../../components/proxy-host-object.json#/properties/locations"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-08T23:23:03.000Z",
- "modified_on": "2024-10-08T23:26:37.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "forward_host": "192.168.0.10",
- "forward_port": 8989,
- "access_list_id": 0,
- "certificate_id": 0,
- "ssl_forced": false,
- "caching_enabled": false,
- "block_exploits": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "allow_websocket_upgrade": false,
- "http2_support": false,
- "forward_scheme": "http",
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false,
- "owner": {
- "id": 1,
- "created_on": "2024-10-07T22:43:55.000Z",
- "modified_on": "2024-10-08T12:52:54.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "some guy",
- "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
- "roles": ["admin"]
- },
- "certificate": null,
- "access_list": null
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/proxy-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/proxy-hosts/post.json b/backend/schema/paths/nginx/proxy-hosts/post.json
deleted file mode 100644
index 85455fb6..00000000
--- a/backend/schema/paths/nginx/proxy-hosts/post.json
+++ /dev/null
@@ -1,128 +0,0 @@
-{
- "operationId": "createProxyHost",
- "summary": "Create a Proxy Host",
- "tags": ["Proxy Hosts"],
- "security": [
- {
- "BearerAuth": ["proxy_hosts"]
- }
- ],
- "requestBody": {
- "description": "Proxy Host Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["domain_names", "forward_scheme", "forward_host", "forward_port"],
- "properties": {
- "domain_names": {
- "$ref": "../../../components/proxy-host-object.json#/properties/domain_names"
- },
- "forward_scheme": {
- "$ref": "../../../components/proxy-host-object.json#/properties/forward_scheme"
- },
- "forward_host": {
- "$ref": "../../../components/proxy-host-object.json#/properties/forward_host"
- },
- "forward_port": {
- "$ref": "../../../components/proxy-host-object.json#/properties/forward_port"
- },
- "certificate_id": {
- "$ref": "../../../components/proxy-host-object.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../../../components/proxy-host-object.json#/properties/ssl_forced"
- },
- "hsts_enabled": {
- "$ref": "../../../components/proxy-host-object.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../../../components/proxy-host-object.json#/properties/hsts_subdomains"
- },
- "http2_support": {
- "$ref": "../../../components/proxy-host-object.json#/properties/http2_support"
- },
- "block_exploits": {
- "$ref": "../../../components/proxy-host-object.json#/properties/block_exploits"
- },
- "caching_enabled": {
- "$ref": "../../../components/proxy-host-object.json#/properties/caching_enabled"
- },
- "allow_websocket_upgrade": {
- "$ref": "../../../components/proxy-host-object.json#/properties/allow_websocket_upgrade"
- },
- "access_list_id": {
- "$ref": "../../../components/proxy-host-object.json#/properties/access_list_id"
- },
- "advanced_config": {
- "$ref": "../../../components/proxy-host-object.json#/properties/advanced_config"
- },
- "enabled": {
- "$ref": "../../../components/proxy-host-object.json#/properties/enabled"
- },
- "meta": {
- "$ref": "../../../components/proxy-host-object.json#/properties/meta"
- },
- "locations": {
- "$ref": "../../../components/proxy-host-object.json#/properties/locations"
- }
- }
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "201 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-08T23:23:03.000Z",
- "modified_on": "2024-10-08T23:23:03.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "forward_host": "127.0.0.1",
- "forward_port": 8989,
- "access_list_id": 0,
- "certificate_id": 0,
- "ssl_forced": false,
- "caching_enabled": false,
- "block_exploits": false,
- "advanced_config": "",
- "meta": {},
- "allow_websocket_upgrade": false,
- "http2_support": false,
- "forward_scheme": "http",
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false,
- "certificate": null,
- "owner": {
- "id": 1,
- "created_on": "2024-10-07T22:43:55.000Z",
- "modified_on": "2024-10-08T12:52:54.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "some guy",
- "avatar": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?default=mm",
- "roles": ["admin"]
- },
- "access_list": null
- }
- }
- },
- "schema": {
- "$ref": "../../../components/proxy-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/redirection-hosts/get.json b/backend/schema/paths/nginx/redirection-hosts/get.json
deleted file mode 100644
index 0b35e0fc..00000000
--- a/backend/schema/paths/nginx/redirection-hosts/get.json
+++ /dev/null
@@ -1,62 +0,0 @@
-{
- "operationId": "getRedirectionHosts",
- "summary": "Get all Redirection hosts",
- "tags": ["Redirection Hosts"],
- "security": [
- {
- "BearerAuth": ["redirection_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "query",
- "name": "expand",
- "description": "Expansions",
- "schema": {
- "type": "string",
- "enum": ["owner", "certificate"]
- }
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": 1,
- "created_on": "2024-10-09T01:13:12.000Z",
- "modified_on": "2024-10-09T01:13:13.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "forward_domain_name": "something-else.com",
- "preserve_path": false,
- "certificate_id": 0,
- "ssl_forced": false,
- "block_exploits": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "http2_support": false,
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false,
- "forward_scheme": "http",
- "forward_http_code": 301
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../../components/redirection-host-list.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/delete.json b/backend/schema/paths/nginx/redirection-hosts/hostID/delete.json
deleted file mode 100644
index 7330f362..00000000
--- a/backend/schema/paths/nginx/redirection-hosts/hostID/delete.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "operationId": "deleteRedirectionHost",
- "summary": "Delete a Redirection Host",
- "tags": ["Redirection Hosts"],
- "security": [
- {
- "BearerAuth": ["redirection_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json b/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json
deleted file mode 100644
index 8433220d..00000000
--- a/backend/schema/paths/nginx/redirection-hosts/hostID/disable/post.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "operationId": "disableRedirectionHost",
- "summary": "Disable a Redirection Host",
- "tags": ["Redirection Hosts"],
- "security": [
- {
- "BearerAuth": ["redirection_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Host is already disabled"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json b/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json
deleted file mode 100644
index bef53436..00000000
--- a/backend/schema/paths/nginx/redirection-hosts/hostID/enable/post.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "operationId": "enableRedirectionHost",
- "summary": "Enable a Redirection Host",
- "tags": ["Redirection Hosts"],
- "security": [
- {
- "BearerAuth": ["redirection_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Host is already enabled"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/get.json b/backend/schema/paths/nginx/redirection-hosts/hostID/get.json
deleted file mode 100644
index d780f874..00000000
--- a/backend/schema/paths/nginx/redirection-hosts/hostID/get.json
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- "operationId": "getRedirectionHost",
- "summary": "Get a Redirection Host",
- "tags": ["Redirection Hosts"],
- "security": [
- {
- "BearerAuth": ["redirection_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 1
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T01:13:12.000Z",
- "modified_on": "2024-10-09T01:13:13.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "forward_domain_name": "something-else.com",
- "preserve_path": false,
- "certificate_id": 0,
- "ssl_forced": false,
- "block_exploits": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "http2_support": false,
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false,
- "forward_scheme": "http",
- "forward_http_code": 301
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/redirection-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/redirection-hosts/hostID/put.json b/backend/schema/paths/nginx/redirection-hosts/hostID/put.json
deleted file mode 100644
index fd97cbfa..00000000
--- a/backend/schema/paths/nginx/redirection-hosts/hostID/put.json
+++ /dev/null
@@ -1,128 +0,0 @@
-{
- "operationId": "updateRedirectionHost",
- "summary": "Update a Redirection Host",
- "tags": ["Redirection Hosts"],
- "security": [
- {
- "BearerAuth": ["redirection_hosts"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "hostID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "requestBody": {
- "description": "Redirection Host Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "domain_names": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/domain_names"
- },
- "forward_http_code": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/forward_http_code"
- },
- "forward_scheme": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/forward_scheme"
- },
- "forward_domain_name": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/forward_domain_name"
- },
- "preserve_path": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/preserve_path"
- },
- "certificate_id": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/ssl_forced"
- },
- "hsts_enabled": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/hsts_subdomains"
- },
- "http2_support": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/http2_support"
- },
- "block_exploits": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/block_exploits"
- },
- "advanced_config": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/advanced_config"
- },
- "meta": {
- "$ref": "../../../../components/redirection-host-object.json#/properties/meta"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T01:13:12.000Z",
- "modified_on": "2024-10-09T01:18:11.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "forward_domain_name": "something-else.com",
- "preserve_path": false,
- "certificate_id": 0,
- "ssl_forced": false,
- "block_exploits": false,
- "advanced_config": "",
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "http2_support": false,
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false,
- "forward_scheme": "http",
- "forward_http_code": 301,
- "owner": {
- "id": 1,
- "created_on": "2024-10-09T00:59:56.000Z",
- "modified_on": "2024-10-09T00:59:56.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "Admin",
- "avatar": "",
- "roles": ["admin"]
- },
- "certificate": null
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/redirection-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/redirection-hosts/post.json b/backend/schema/paths/nginx/redirection-hosts/post.json
deleted file mode 100644
index 5bfde2c3..00000000
--- a/backend/schema/paths/nginx/redirection-hosts/post.json
+++ /dev/null
@@ -1,113 +0,0 @@
-{
- "operationId": "createRedirectionHost",
- "summary": "Create a Redirection Host",
- "tags": ["Redirection Hosts"],
- "security": [
- {
- "BearerAuth": ["redirection_hosts"]
- }
- ],
- "requestBody": {
- "description": "Redirection Host Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["domain_names", "forward_scheme", "forward_http_code", "forward_domain_name"],
- "properties": {
- "domain_names": {
- "$ref": "../../../components/redirection-host-object.json#/properties/domain_names"
- },
- "forward_http_code": {
- "$ref": "../../../components/redirection-host-object.json#/properties/forward_http_code"
- },
- "forward_scheme": {
- "$ref": "../../../components/redirection-host-object.json#/properties/forward_scheme"
- },
- "forward_domain_name": {
- "$ref": "../../../components/redirection-host-object.json#/properties/forward_domain_name"
- },
- "preserve_path": {
- "$ref": "../../../components/redirection-host-object.json#/properties/preserve_path"
- },
- "certificate_id": {
- "$ref": "../../../components/redirection-host-object.json#/properties/certificate_id"
- },
- "ssl_forced": {
- "$ref": "../../../components/redirection-host-object.json#/properties/ssl_forced"
- },
- "hsts_enabled": {
- "$ref": "../../../components/redirection-host-object.json#/properties/hsts_enabled"
- },
- "hsts_subdomains": {
- "$ref": "../../../components/redirection-host-object.json#/properties/hsts_subdomains"
- },
- "http2_support": {
- "$ref": "../../../components/redirection-host-object.json#/properties/http2_support"
- },
- "block_exploits": {
- "$ref": "../../../components/redirection-host-object.json#/properties/block_exploits"
- },
- "advanced_config": {
- "$ref": "../../../components/redirection-host-object.json#/properties/advanced_config"
- },
- "meta": {
- "$ref": "../../../components/redirection-host-object.json#/properties/meta"
- }
- }
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "201 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T01:13:12.000Z",
- "modified_on": "2024-10-09T01:13:12.000Z",
- "owner_user_id": 1,
- "domain_names": ["test.example.com"],
- "forward_domain_name": "something-else.com",
- "preserve_path": false,
- "certificate_id": 0,
- "ssl_forced": false,
- "block_exploits": false,
- "advanced_config": "",
- "meta": {},
- "http2_support": false,
- "enabled": true,
- "hsts_enabled": false,
- "hsts_subdomains": false,
- "forward_scheme": "http",
- "forward_http_code": 301,
- "certificate": null,
- "owner": {
- "id": 1,
- "created_on": "2024-10-09T00:59:56.000Z",
- "modified_on": "2024-10-09T00:59:56.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "Admin",
- "avatar": "",
- "roles": ["admin"]
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../components/redirection-host-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/streams/get.json b/backend/schema/paths/nginx/streams/get.json
deleted file mode 100644
index 17969ee4..00000000
--- a/backend/schema/paths/nginx/streams/get.json
+++ /dev/null
@@ -1,56 +0,0 @@
-{
- "operationId": "getStreams",
- "summary": "Get all streams",
- "tags": ["Streams"],
- "security": [
- {
- "BearerAuth": ["streams"]
- }
- ],
- "parameters": [
- {
- "in": "query",
- "name": "expand",
- "description": "Expansions",
- "schema": {
- "type": "string",
- "enum": ["owner", "certificate"]
- }
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": 1,
- "created_on": "2024-10-09T02:33:45.000Z",
- "modified_on": "2024-10-09T02:33:45.000Z",
- "owner_user_id": 1,
- "incoming_port": 9090,
- "forwarding_host": "router.internal",
- "forwarding_port": 80,
- "tcp_forwarding": true,
- "udp_forwarding": false,
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "enabled": true,
- "certificate_id": 0
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../../components/stream-list.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/streams/post.json b/backend/schema/paths/nginx/streams/post.json
deleted file mode 100644
index d26996b6..00000000
--- a/backend/schema/paths/nginx/streams/post.json
+++ /dev/null
@@ -1,91 +0,0 @@
-{
- "operationId": "createStream",
- "summary": "Create a Stream",
- "tags": ["Streams"],
- "security": [
- {
- "BearerAuth": ["streams"]
- }
- ],
- "requestBody": {
- "description": "Stream Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["incoming_port", "forwarding_host", "forwarding_port"],
- "properties": {
- "incoming_port": {
- "$ref": "../../../components/stream-object.json#/properties/incoming_port"
- },
- "forwarding_host": {
- "$ref": "../../../components/stream-object.json#/properties/forwarding_host"
- },
- "forwarding_port": {
- "$ref": "../../../components/stream-object.json#/properties/forwarding_port"
- },
- "tcp_forwarding": {
- "$ref": "../../../components/stream-object.json#/properties/tcp_forwarding"
- },
- "udp_forwarding": {
- "$ref": "../../../components/stream-object.json#/properties/udp_forwarding"
- },
- "certificate_id": {
- "$ref": "../../../components/stream-object.json#/properties/certificate_id"
- },
- "meta": {
- "$ref": "../../../components/stream-object.json#/properties/meta"
- }
- }
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "201 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T02:33:45.000Z",
- "modified_on": "2024-10-09T02:33:45.000Z",
- "owner_user_id": 1,
- "incoming_port": 9090,
- "forwarding_host": "router.internal",
- "forwarding_port": 80,
- "tcp_forwarding": true,
- "udp_forwarding": false,
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "enabled": true,
- "owner": {
- "id": 1,
- "created_on": "2024-10-09T02:33:16.000Z",
- "modified_on": "2024-10-09T02:33:16.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "Admin",
- "avatar": "",
- "roles": ["admin"]
- },
- "certificate_id": 0
- }
- }
- },
- "schema": {
- "$ref": "../../../components/stream-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/streams/streamID/delete.json b/backend/schema/paths/nginx/streams/streamID/delete.json
deleted file mode 100644
index 3a968525..00000000
--- a/backend/schema/paths/nginx/streams/streamID/delete.json
+++ /dev/null
@@ -1,39 +0,0 @@
-{
- "operationId": "deleteStream",
- "summary": "Delete a Stream",
- "tags": ["Streams"],
- "security": [
- {
- "BearerAuth": ["streams"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "streamID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/streams/streamID/disable/post.json b/backend/schema/paths/nginx/streams/streamID/disable/post.json
deleted file mode 100644
index d1c1b1c8..00000000
--- a/backend/schema/paths/nginx/streams/streamID/disable/post.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "operationId": "disableStream",
- "summary": "Disable a Stream",
- "tags": ["Streams"],
- "security": [
- {
- "BearerAuth": ["streams"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "streamID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Host is already disabled"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/streams/streamID/enable/post.json b/backend/schema/paths/nginx/streams/streamID/enable/post.json
deleted file mode 100644
index dc914f5f..00000000
--- a/backend/schema/paths/nginx/streams/streamID/enable/post.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "operationId": "enableStream",
- "summary": "Enable a Stream",
- "tags": ["Streams"],
- "security": [
- {
- "BearerAuth": ["streams"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "streamID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- },
- "400": {
- "description": "400 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "error": {
- "code": 400,
- "message": "Host is already enabled"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../../../../components/error.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/streams/streamID/get.json b/backend/schema/paths/nginx/streams/streamID/get.json
deleted file mode 100644
index 801af13a..00000000
--- a/backend/schema/paths/nginx/streams/streamID/get.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "operationId": "getStream",
- "summary": "Get a Stream",
- "tags": ["Streams"],
- "security": [
- {
- "BearerAuth": ["streams"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "streamID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T02:33:45.000Z",
- "modified_on": "2024-10-09T02:33:45.000Z",
- "owner_user_id": 1,
- "incoming_port": 9090,
- "forwarding_host": "router.internal",
- "forwarding_port": 80,
- "tcp_forwarding": true,
- "udp_forwarding": false,
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "enabled": true,
- "certificate_id": 0
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/stream-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/nginx/streams/streamID/put.json b/backend/schema/paths/nginx/streams/streamID/put.json
deleted file mode 100644
index 14adb163..00000000
--- a/backend/schema/paths/nginx/streams/streamID/put.json
+++ /dev/null
@@ -1,103 +0,0 @@
-{
- "operationId": "updateStream",
- "summary": "Update a Stream",
- "tags": ["Streams"],
- "security": [
- {
- "BearerAuth": ["streams"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "streamID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "example": 2
- }
- ],
- "requestBody": {
- "description": "Stream Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "incoming_port": {
- "$ref": "../../../../components/stream-object.json#/properties/incoming_port"
- },
- "forwarding_host": {
- "$ref": "../../../../components/stream-object.json#/properties/forwarding_host"
- },
- "forwarding_port": {
- "$ref": "../../../../components/stream-object.json#/properties/forwarding_port"
- },
- "tcp_forwarding": {
- "$ref": "../../../../components/stream-object.json#/properties/tcp_forwarding"
- },
- "udp_forwarding": {
- "$ref": "../../../../components/stream-object.json#/properties/udp_forwarding"
- },
- "certificate_id": {
- "$ref": "../../../../components/stream-object.json#/properties/certificate_id"
- },
- "meta": {
- "$ref": "../../../../components/stream-object.json#/properties/meta"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2024-10-09T02:33:45.000Z",
- "modified_on": "2024-10-09T02:33:45.000Z",
- "owner_user_id": 1,
- "incoming_port": 9090,
- "forwarding_host": "router.internal",
- "forwarding_port": 80,
- "tcp_forwarding": true,
- "udp_forwarding": false,
- "meta": {
- "nginx_online": true,
- "nginx_err": null
- },
- "enabled": true,
- "owner": {
- "id": 1,
- "created_on": "2024-10-09T02:33:16.000Z",
- "modified_on": "2024-10-09T02:33:16.000Z",
- "is_deleted": false,
- "is_disabled": false,
- "email": "admin@example.com",
- "name": "Administrator",
- "nickname": "Admin",
- "avatar": "",
- "roles": ["admin"]
- },
- "certificate_id": 0
- }
- }
- },
- "schema": {
- "$ref": "../../../../components/stream-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/reports/hosts/get.json b/backend/schema/paths/reports/hosts/get.json
deleted file mode 100644
index a40ddc72..00000000
--- a/backend/schema/paths/reports/hosts/get.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
- "operationId": "reportsHosts",
- "summary": "Report on Host Statistics",
- "tags": ["Reports"],
- "security": [
- {
- "BearerAuth": ["reports"]
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "proxy": 20,
- "redirection": 1,
- "stream": 0,
- "dead": 1
- }
- }
- },
- "schema": {
- "type": "object",
- "properties": {
- "proxy": {
- "type": "integer",
- "description": "Proxy Hosts Count"
- },
- "redirection": {
- "type": "integer",
- "description": "Redirection Hosts Count"
- },
- "stream": {
- "type": "integer",
- "description": "Streams Count"
- },
- "dead": {
- "type": "integer",
- "description": "404 Hosts Count"
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/schema/get.json b/backend/schema/paths/schema/get.json
deleted file mode 100644
index d435b004..00000000
--- a/backend/schema/paths/schema/get.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "operationId": "schema",
- "summary": "Returns this swagger API schema",
- "tags": ["Public"],
- "responses": {
- "200": {
- "description": "200 response"
- }
- }
-}
diff --git a/backend/schema/paths/settings/get.json b/backend/schema/paths/settings/get.json
deleted file mode 100644
index 5d148d8a..00000000
--- a/backend/schema/paths/settings/get.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
- "operationId": "getSettings",
- "summary": "Get all settings",
- "tags": ["Settings"],
- "security": [
- {
- "BearerAuth": ["settings"]
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": "default-site",
- "name": "Default Site",
- "description": "What to show when Nginx is hit with an unknown Host",
- "value": "congratulations",
- "meta": {}
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../components/setting-list.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/settings/settingID/get.json b/backend/schema/paths/settings/settingID/get.json
deleted file mode 100644
index 405b976d..00000000
--- a/backend/schema/paths/settings/settingID/get.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "operationId": "getSetting",
- "summary": "Get a setting",
- "tags": ["Settings"],
- "security": [
- {
- "BearerAuth": ["settings"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "settingID",
- "schema": {
- "type": "string",
- "minLength": 1
- },
- "required": true,
- "description": "Setting ID",
- "example": "default-site"
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": "default-site",
- "name": "Default Site",
- "description": "What to show when Nginx is hit with an unknown Host",
- "value": "congratulations",
- "meta": {}
- }
- }
- },
- "schema": {
- "$ref": "../../../components/setting-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/settings/settingID/put.json b/backend/schema/paths/settings/settingID/put.json
deleted file mode 100644
index 4ca62429..00000000
--- a/backend/schema/paths/settings/settingID/put.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
- "operationId": "updateSetting",
- "summary": "Update a setting",
- "tags": ["Settings"],
- "security": [
- {
- "BearerAuth": ["settings"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "settingID",
- "schema": {
- "type": "string",
- "minLength": 1,
- "enum": ["default-site"]
- },
- "required": true,
- "description": "Setting ID",
- "example": "default-site"
- }
- ],
- "requestBody": {
- "description": "Setting Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "value": {
- "type": "string",
- "minLength": 1,
- "enum": ["congratulations", "404", "444", "redirect", "html"]
- },
- "meta": {
- "type": "object",
- "additionalProperties": false,
- "properties": {
- "redirect": {
- "type": "string"
- },
- "html": {
- "type": "string"
- }
- }
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": "default-site",
- "name": "Default Site",
- "description": "What to show when Nginx is hit with an unknown Host",
- "value": "congratulations",
- "meta": {}
- }
- }
- },
- "schema": {
- "$ref": "../../../components/setting-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/tokens/get.json b/backend/schema/paths/tokens/get.json
deleted file mode 100644
index ef842eaf..00000000
--- a/backend/schema/paths/tokens/get.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "operationId": "refreshToken",
- "summary": "Refresh your access token",
- "tags": ["Tokens"],
- "security": [
- {
- "BearerAuth": ["tokens"]
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "expires": "2025-02-04T20:40:46.340Z",
- "token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
- }
- }
- },
- "schema": {
- "$ref": "../../components/token-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/tokens/post.json b/backend/schema/paths/tokens/post.json
deleted file mode 100644
index 99703ff0..00000000
--- a/backend/schema/paths/tokens/post.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "operationId": "requestToken",
- "summary": "Request a new access token from credentials",
- "tags": ["Tokens"],
- "requestBody": {
- "description": "Credentials Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "additionalProperties": false,
- "properties": {
- "identity": {
- "minLength": 1,
- "type": "string"
- },
- "scope": {
- "minLength": 1,
- "type": "string",
- "enum": ["user"]
- },
- "secret": {
- "minLength": 1,
- "type": "string"
- }
- },
- "required": ["identity", "secret"],
- "type": "object"
- }
- }
- }
- },
- "responses": {
- "200": {
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "result": {
- "expires": "2025-02-04T20:40:46.340Z",
- "token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../components/token-object.json"
- }
- }
- },
- "description": "200 response"
- }
- }
-}
diff --git a/backend/schema/paths/users/get.json b/backend/schema/paths/users/get.json
deleted file mode 100644
index 37415301..00000000
--- a/backend/schema/paths/users/get.json
+++ /dev/null
@@ -1,74 +0,0 @@
-{
- "operationId": "getUsers",
- "summary": "Get all users",
- "tags": ["Users"],
- "security": [
- {
- "BearerAuth": ["users"]
- }
- ],
- "parameters": [
- {
- "in": "query",
- "name": "expand",
- "description": "Expansions",
- "schema": {
- "type": "string",
- "enum": ["permissions"]
- }
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": [
- {
- "id": 1,
- "created_on": "2020-01-30T09:36:08.000Z",
- "modified_on": "2020-01-30T09:41:04.000Z",
- "is_disabled": false,
- "email": "jc@jc21.com",
- "name": "Jamie Curnow",
- "nickname": "James",
- "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
- "roles": ["admin"]
- }
- ]
- },
- "withPermissions": {
- "value": [
- {
- "id": 1,
- "created_on": "2020-01-30T09:36:08.000Z",
- "modified_on": "2020-01-30T09:41:04.000Z",
- "is_disabled": false,
- "email": "jc@jc21.com",
- "name": "Jamie Curnow",
- "nickname": "James",
- "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
- "roles": ["admin"],
- "permissions": {
- "visibility": "all",
- "proxy_hosts": "manage",
- "redirection_hosts": "manage",
- "dead_hosts": "manage",
- "streams": "manage",
- "access_lists": "manage",
- "certificates": "manage"
- }
- }
- ]
- }
- },
- "schema": {
- "$ref": "../../components/user-list.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/users/post.json b/backend/schema/paths/users/post.json
deleted file mode 100644
index c0213fe0..00000000
--- a/backend/schema/paths/users/post.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "operationId": "createUser",
- "summary": "Create a User",
- "tags": ["Users"],
- "security": [
- {
- "BearerAuth": ["users"]
- }
- ],
- "requestBody": {
- "description": "User Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "required": ["name", "nickname", "email"],
- "properties": {
- "name": {
- "$ref": "../../components/user-object.json#/properties/name"
- },
- "nickname": {
- "$ref": "../../components/user-object.json#/properties/nickname"
- },
- "email": {
- "$ref": "../../components/user-object.json#/properties/email"
- },
- "roles": {
- "$ref": "../../components/user-object.json#/properties/roles"
- },
- "is_disabled": {
- "$ref": "../../components/user-object.json#/properties/is_disabled"
- },
- "auth": {
- "type": "object",
- "description": "Auth Credentials",
- "example": {
- "type": "password",
- "secret": "bigredhorsebanana"
- }
- }
- }
- }
- }
- }
- },
- "responses": {
- "201": {
- "description": "201 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 2,
- "created_on": "2020-01-30T09:41:04.000Z",
- "modified_on": "2020-01-30T09:41:04.000Z",
- "is_disabled": false,
- "email": "jc@jc21.com",
- "name": "Jamie Curnow",
- "nickname": "James",
- "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
- "roles": ["admin"],
- "permissions": {
- "id": 3,
- "created_on": "2020-01-30T09:41:04.000Z",
- "modified_on": "2020-01-30T09:41:04.000Z",
- "user_id": 2,
- "visibility": "user",
- "proxy_hosts": "manage",
- "redirection_hosts": "manage",
- "dead_hosts": "manage",
- "streams": "manage",
- "access_lists": "manage",
- "certificates": "manage"
- }
- }
- }
- },
- "schema": {
- "$ref": "../../components/user-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/users/userID/auth/put.json b/backend/schema/paths/users/userID/auth/put.json
deleted file mode 100644
index a72f5617..00000000
--- a/backend/schema/paths/users/userID/auth/put.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
- "operationId": "updateUserAuth",
- "summary": "Update a User's Authentication",
- "tags": ["Users"],
- "security": [
- {
- "BearerAuth": ["users"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "userID",
- "schema": {
- "oneOf": [
- {
- "type": "string",
- "pattern": "^me$"
- },
- {
- "type": "integer",
- "minimum": 1
- }
- ]
- },
- "required": true,
- "description": "User ID or 'me' for yourself",
- "example": 2
- }
- ],
- "requestBody": {
- "description": "Auth Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "required": ["type", "secret"],
- "properties": {
- "type": {
- "type": "string",
- "pattern": "^password$",
- "example": "password"
- },
- "current": {
- "type": "string",
- "minLength": 1,
- "maxLength": 64,
- "example": "changeme"
- },
- "secret": {
- "type": "string",
- "minLength": 8,
- "maxLength": 64,
- "example": "mySuperN3wP@ssword!"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/users/userID/delete.json b/backend/schema/paths/users/userID/delete.json
deleted file mode 100644
index 7d4f3615..00000000
--- a/backend/schema/paths/users/userID/delete.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "operationId": "deleteUser",
- "summary": "Delete a User",
- "tags": ["Users"],
- "security": [
- {
- "BearerAuth": ["users"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "userID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "description": "User ID",
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/users/userID/get.json b/backend/schema/paths/users/userID/get.json
deleted file mode 100644
index cb8ac61b..00000000
--- a/backend/schema/paths/users/userID/get.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
- "operationId": "getUser",
- "summary": "Get a user",
- "tags": ["Users"],
- "security": [
- {
- "BearerAuth": ["users"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "userID",
- "schema": {
- "oneOf": [
- {
- "type": "string",
- "pattern": "^me$"
- },
- {
- "type": "integer",
- "minimum": 1
- }
- ]
- },
- "required": true,
- "description": "User ID or 'me' for yourself",
- "example": 1
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 1,
- "created_on": "2020-01-30T09:36:08.000Z",
- "modified_on": "2020-01-30T09:41:04.000Z",
- "is_disabled": false,
- "email": "jc@jc21.com",
- "name": "Jamie Curnow",
- "nickname": "James",
- "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
- "roles": ["admin"]
- }
- }
- },
- "schema": {
- "$ref": "../../../components/user-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/users/userID/login/post.json b/backend/schema/paths/users/userID/login/post.json
deleted file mode 100644
index 6148d182..00000000
--- a/backend/schema/paths/users/userID/login/post.json
+++ /dev/null
@@ -1,73 +0,0 @@
-{
- "operationId": "loginAsUser",
- "summary": "Login as this user",
- "tags": ["Users"],
- "security": [
- {
- "BearerAuth": ["users"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "userID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "description": "User ID",
- "example": 2
- }
- ],
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "token": "eyJhbGciOiJSUzI1NiIsInR...16OjT8B3NLyXg",
- "expires": "2020-01-31T10:56:23.239Z",
- "user": {
- "id": 1,
- "created_on": "2020-01-30T10:43:44.000Z",
- "modified_on": "2020-01-30T10:43:44.000Z",
- "is_disabled": false,
- "email": "jc@jc21.com",
- "name": "Jamie Curnow",
- "nickname": "James",
- "avatar": "//www.gravatar.com/avatar/3c8d73f45fd8763f827b964c76e6032a?default=mm",
- "roles": ["admin"]
- }
- }
- }
- },
- "schema": {
- "type": "object",
- "description": "Login object",
- "required": ["expires", "token", "user"],
- "additionalProperties": false,
- "properties": {
- "expires": {
- "description": "Token Expiry Unix Time",
- "example": 1566540249,
- "minimum": 1,
- "type": "number"
- },
- "token": {
- "description": "JWT Token",
- "example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4",
- "type": "string"
- },
- "user": {
- "$ref": "../../../../components/user-object.json"
- }
- }
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/users/userID/permissions/put.json b/backend/schema/paths/users/userID/permissions/put.json
deleted file mode 100644
index 2dcd2aed..00000000
--- a/backend/schema/paths/users/userID/permissions/put.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "operationId": "updateUserPermissions",
- "summary": "Update a User's Permissions",
- "tags": ["Users"],
- "security": [
- {
- "BearerAuth": ["users"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "userID",
- "schema": {
- "type": "integer",
- "minimum": 1
- },
- "required": true,
- "description": "User ID",
- "example": 2
- }
- ],
- "requestBody": {
- "description": "Permissions Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "$ref": "../../../../components/permission-object.json"
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": true
- }
- },
- "schema": {
- "type": "boolean"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/paths/users/userID/put.json b/backend/schema/paths/users/userID/put.json
deleted file mode 100644
index 60a6cd13..00000000
--- a/backend/schema/paths/users/userID/put.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "operationId": "updateUser",
- "summary": "Update a User",
- "tags": ["Users"],
- "security": [
- {
- "BearerAuth": ["users"]
- }
- ],
- "parameters": [
- {
- "in": "path",
- "name": "userID",
- "schema": {
- "oneOf": [
- {
- "type": "string",
- "pattern": "^me$"
- },
- {
- "type": "integer",
- "minimum": 1
- }
- ]
- },
- "required": true,
- "description": "User ID or 'me' for yourself",
- "example": 2
- }
- ],
- "requestBody": {
- "description": "User Payload",
- "required": true,
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": false,
- "minProperties": 1,
- "properties": {
- "name": {
- "$ref": "../../../components/user-object.json#/properties/name"
- },
- "nickname": {
- "$ref": "../../../components/user-object.json#/properties/nickname"
- },
- "email": {
- "$ref": "../../../components/user-object.json#/properties/email"
- },
- "roles": {
- "$ref": "../../../components/user-object.json#/properties/roles"
- },
- "is_disabled": {
- "$ref": "../../../components/user-object.json#/properties/is_disabled"
- }
- }
- }
- }
- }
- },
- "responses": {
- "200": {
- "description": "200 response",
- "content": {
- "application/json": {
- "examples": {
- "default": {
- "value": {
- "id": 2,
- "created_on": "2020-01-30T09:36:08.000Z",
- "modified_on": "2020-01-30T09:41:04.000Z",
- "is_disabled": false,
- "email": "jc@jc21.com",
- "name": "Jamie Curnow",
- "nickname": "James",
- "avatar": "//www.gravatar.com/avatar/6193176330f8d38747f038c170ddb193?default=mm",
- "roles": ["admin"]
- }
- }
- },
- "schema": {
- "$ref": "../../../components/user-object.json"
- }
- }
- }
- }
- }
-}
diff --git a/backend/schema/swagger.json b/backend/schema/swagger.json
deleted file mode 100644
index 4a502b4e..00000000
--- a/backend/schema/swagger.json
+++ /dev/null
@@ -1,274 +0,0 @@
-{
- "openapi": "3.1.0",
- "info": {
- "title": "Nginx Proxy Manager API",
- "version": "2.x.x"
- },
- "servers": [
- {
- "url": "http://127.0.0.1:81/api"
- }
- ],
- "components": {
- "securitySchemes": {
- "bearerAuth": {
- "type": "http",
- "scheme": "bearer",
- "bearerFormat": "JWT"
- }
- }
- },
- "paths": {
- "/": {
- "get": {
- "$ref": "./paths/get.json"
- }
- },
- "/audit-log": {
- "get": {
- "$ref": "./paths/audit-log/get.json"
- }
- },
- "/nginx/access-lists": {
- "get": {
- "$ref": "./paths/nginx/access-lists/get.json"
- },
- "post": {
- "$ref": "./paths/nginx/access-lists/post.json"
- }
- },
- "/nginx/access-lists/{listID}": {
- "get": {
- "$ref": "./paths/nginx/access-lists/listID/get.json"
- },
- "put": {
- "$ref": "./paths/nginx/access-lists/listID/put.json"
- },
- "delete": {
- "$ref": "./paths/nginx/access-lists/listID/delete.json"
- }
- },
- "/nginx/certificates": {
- "get": {
- "$ref": "./paths/nginx/certificates/get.json"
- },
- "post": {
- "$ref": "./paths/nginx/certificates/post.json"
- }
- },
- "/nginx/certificates/validate": {
- "post": {
- "$ref": "./paths/nginx/certificates/validate/post.json"
- }
- },
- "/nginx/certificates/test-http": {
- "get": {
- "$ref": "./paths/nginx/certificates/test-http/get.json"
- }
- },
- "/nginx/certificates/{certID}": {
- "get": {
- "$ref": "./paths/nginx/certificates/certID/get.json"
- },
- "delete": {
- "$ref": "./paths/nginx/certificates/certID/delete.json"
- }
- },
- "/nginx/certificates/{certID}/download": {
- "get": {
- "$ref": "./paths/nginx/certificates/certID/download/get.json"
- }
- },
- "/nginx/certificates/{certID}/renew": {
- "post": {
- "$ref": "./paths/nginx/certificates/certID/renew/post.json"
- }
- },
- "/nginx/certificates/{certID}/upload": {
- "post": {
- "$ref": "./paths/nginx/certificates/certID/upload/post.json"
- }
- },
- "/nginx/proxy-hosts": {
- "get": {
- "$ref": "./paths/nginx/proxy-hosts/get.json"
- },
- "post": {
- "$ref": "./paths/nginx/proxy-hosts/post.json"
- }
- },
- "/nginx/proxy-hosts/{hostID}": {
- "get": {
- "$ref": "./paths/nginx/proxy-hosts/hostID/get.json"
- },
- "put": {
- "$ref": "./paths/nginx/proxy-hosts/hostID/put.json"
- },
- "delete": {
- "$ref": "./paths/nginx/proxy-hosts/hostID/delete.json"
- }
- },
- "/nginx/proxy-hosts/{hostID}/enable": {
- "post": {
- "$ref": "./paths/nginx/proxy-hosts/hostID/enable/post.json"
- }
- },
- "/nginx/proxy-hosts/{hostID}/disable": {
- "post": {
- "$ref": "./paths/nginx/proxy-hosts/hostID/disable/post.json"
- }
- },
- "/nginx/redirection-hosts": {
- "get": {
- "$ref": "./paths/nginx/redirection-hosts/get.json"
- },
- "post": {
- "$ref": "./paths/nginx/redirection-hosts/post.json"
- }
- },
- "/nginx/redirection-hosts/{hostID}": {
- "get": {
- "$ref": "./paths/nginx/redirection-hosts/hostID/get.json"
- },
- "put": {
- "$ref": "./paths/nginx/redirection-hosts/hostID/put.json"
- },
- "delete": {
- "$ref": "./paths/nginx/redirection-hosts/hostID/delete.json"
- }
- },
- "/nginx/redirection-hosts/{hostID}/enable": {
- "post": {
- "$ref": "./paths/nginx/redirection-hosts/hostID/enable/post.json"
- }
- },
- "/nginx/redirection-hosts/{hostID}/disable": {
- "post": {
- "$ref": "./paths/nginx/redirection-hosts/hostID/disable/post.json"
- }
- },
- "/nginx/dead-hosts": {
- "get": {
- "$ref": "./paths/nginx/dead-hosts/get.json"
- },
- "post": {
- "$ref": "./paths/nginx/dead-hosts/post.json"
- }
- },
- "/nginx/dead-hosts/{hostID}": {
- "get": {
- "$ref": "./paths/nginx/dead-hosts/hostID/get.json"
- },
- "put": {
- "$ref": "./paths/nginx/dead-hosts/hostID/put.json"
- },
- "delete": {
- "$ref": "./paths/nginx/dead-hosts/hostID/delete.json"
- }
- },
- "/nginx/dead-hosts/{hostID}/enable": {
- "post": {
- "$ref": "./paths/nginx/dead-hosts/hostID/enable/post.json"
- }
- },
- "/nginx/dead-hosts/{hostID}/disable": {
- "post": {
- "$ref": "./paths/nginx/dead-hosts/hostID/disable/post.json"
- }
- },
- "/nginx/streams": {
- "get": {
- "$ref": "./paths/nginx/streams/get.json"
- },
- "post": {
- "$ref": "./paths/nginx/streams/post.json"
- }
- },
- "/nginx/streams/{streamID}": {
- "get": {
- "$ref": "./paths/nginx/streams/streamID/get.json"
- },
- "put": {
- "$ref": "./paths/nginx/streams/streamID/put.json"
- },
- "delete": {
- "$ref": "./paths/nginx/streams/streamID/delete.json"
- }
- },
- "/nginx/streams/{streamID}/enable": {
- "post": {
- "$ref": "./paths/nginx/streams/streamID/enable/post.json"
- }
- },
- "/nginx/streams/{streamID}/disable": {
- "post": {
- "$ref": "./paths/nginx/streams/streamID/disable/post.json"
- }
- },
- "/reports/hosts": {
- "get": {
- "$ref": "./paths/reports/hosts/get.json"
- }
- },
- "/schema": {
- "get": {
- "$ref": "./paths/schema/get.json"
- }
- },
- "/settings": {
- "get": {
- "$ref": "./paths/settings/get.json"
- }
- },
- "/settings/{settingID}": {
- "get": {
- "$ref": "./paths/settings/settingID/get.json"
- },
- "put": {
- "$ref": "./paths/settings/settingID/put.json"
- }
- },
- "/tokens": {
- "get": {
- "$ref": "./paths/tokens/get.json"
- },
- "post": {
- "$ref": "./paths/tokens/post.json"
- }
- },
- "/users": {
- "get": {
- "$ref": "./paths/users/get.json"
- },
- "post": {
- "$ref": "./paths/users/post.json"
- }
- },
- "/users/{userID}": {
- "get": {
- "$ref": "./paths/users/userID/get.json"
- },
- "put": {
- "$ref": "./paths/users/userID/put.json"
- },
- "delete": {
- "$ref": "./paths/users/userID/delete.json"
- }
- },
- "/users/{userID}/auth": {
- "put": {
- "$ref": "./paths/users/userID/auth/put.json"
- }
- },
- "/users/{userID}/permissions": {
- "put": {
- "$ref": "./paths/users/userID/permissions/put.json"
- }
- },
- "/users/{userID}/login": {
- "post": {
- "$ref": "./paths/users/userID/login/post.json"
- }
- }
- }
-}
diff --git a/backend/scripts/install-certbot-plugins b/backend/scripts/install-certbot-plugins
deleted file mode 100755
index bf995410..00000000
--- a/backend/scripts/install-certbot-plugins
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/node
-
-// Usage:
-// Install all plugins defined in `certbot-dns-plugins.json`:
-// ./install-certbot-plugins
-// Install one or more specific plugins:
-// ./install-certbot-plugins route53 cloudflare
-//
-// Usage with a running docker container:
-// docker exec npm_core /command/s6-setuidgid 1000:1000 bash -c "/app/scripts/install-certbot-plugins"
-//
-
-const dnsPlugins = require('../global/certbot-dns-plugins.json');
-const certbot = require('../lib/certbot');
-const logger = require('../logger').certbot;
-const batchflow = require('batchflow');
-
-let hasErrors = false;
-let failingPlugins = [];
-
-let pluginKeys = Object.keys(dnsPlugins);
-if (process.argv.length > 2) {
- pluginKeys = process.argv.slice(2);
-}
-
-batchflow(pluginKeys).sequential()
- .each((i, pluginKey, next) => {
- certbot.installPlugin(pluginKey)
- .then(() => {
- next();
- })
- .catch((err) => {
- hasErrors = true;
- failingPlugins.push(pluginKey);
- next(err);
- });
- })
- .error((err) => {
- logger.error(err.message);
- })
- .end(() => {
- if (hasErrors) {
- logger.error('Some plugins failed to install. Please check the logs above. Failing plugins: ' + '\n - ' + failingPlugins.join('\n - '));
- process.exit(1);
- } else {
- logger.complete('Plugins installed successfully');
- process.exit(0);
- }
- });
diff --git a/backend/setup.js b/backend/setup.js
deleted file mode 100644
index 29208a0d..00000000
--- a/backend/setup.js
+++ /dev/null
@@ -1,171 +0,0 @@
-const config = require('./lib/config');
-const logger = require('./logger').setup;
-const certificateModel = require('./models/certificate');
-const userModel = require('./models/user');
-const userPermissionModel = require('./models/user_permission');
-const utils = require('./lib/utils');
-const authModel = require('./models/auth');
-const settingModel = require('./models/setting');
-const certbot = require('./lib/certbot');
-/**
- * Creates a default admin users if one doesn't already exist in the database
- *
- * @returns {Promise}
- */
-const setupDefaultUser = () => {
- return userModel
- .query()
- .select('id', )
- .where('is_deleted', 0)
- .first()
- .then((row) => {
- if (!row || !row.id) {
- // Create a new user and set password
- const email = (process.env.INITIAL_ADMIN_EMAIL || 'admin@example.com').toLowerCase();
- const password = process.env.INITIAL_ADMIN_PASSWORD || 'changeme';
-
- logger.info(`Creating a new user: ${email} with password: ${password}`);
-
- const data = {
- is_deleted: 0,
- email: email,
- name: 'Administrator',
- nickname: 'Admin',
- avatar: '',
- roles: ['admin'],
- };
-
- return userModel
- .query()
- .insertAndFetch(data)
- .then((user) => {
- return authModel
- .query()
- .insert({
- user_id: user.id,
- type: 'password',
- secret: password,
- meta: {},
- })
- .then(() => {
- return userPermissionModel.query().insert({
- user_id: user.id,
- visibility: 'all',
- proxy_hosts: 'manage',
- redirection_hosts: 'manage',
- dead_hosts: 'manage',
- streams: 'manage',
- access_lists: 'manage',
- certificates: 'manage',
- });
- });
- })
- .then(() => {
- logger.info('Initial admin setup completed');
- });
- } else if (config.debug()) {
- logger.info('Admin user setup not required');
- }
- });
-};
-
-/**
- * Creates default settings if they don't already exist in the database
- *
- * @returns {Promise}
- */
-const setupDefaultSettings = () => {
- return settingModel
- .query()
- .select('id')
- .where({id: 'default-site'})
- .first()
- .then((row) => {
- if (!row || !row.id) {
- settingModel
- .query()
- .insert({
- id: 'default-site',
- name: 'Default Site',
- description: 'What to show when Nginx is hit with an unknown Host',
- value: 'congratulations',
- meta: {},
- })
- .then(() => {
- logger.info('Default settings added');
- });
- }
- if (config.debug()) {
- logger.info('Default setting setup not required');
- }
- });
-};
-
-/**
- * Installs all Certbot plugins which are required for an installed certificate
- *
- * @returns {Promise}
- */
-const setupCertbotPlugins = () => {
- return certificateModel
- .query()
- .where('is_deleted', 0)
- .andWhere('provider', 'letsencrypt')
- .then((certificates) => {
- if (certificates && certificates.length) {
- const plugins = [];
- const promises = [];
-
- certificates.map((certificate) => {
- if (certificate.meta && certificate.meta.dns_challenge === true) {
- if (plugins.indexOf(certificate.meta.dns_provider) === -1) {
- plugins.push(certificate.meta.dns_provider);
- }
-
- // Make sure credentials file exists
- const credentials_loc = `/etc/letsencrypt/credentials/credentials-${certificate.id}`;
- // Escape single quotes and backslashes
- const escapedCredentials = certificate.meta.dns_provider_credentials.replaceAll('\'', '\\\'').replaceAll('\\', '\\\\');
- const credentials_cmd = `[ -f '${credentials_loc}' ] || { mkdir -p /etc/letsencrypt/credentials 2> /dev/null; echo '${escapedCredentials}' > '${credentials_loc}' && chmod 600 '${credentials_loc}'; }`;
- promises.push(utils.exec(credentials_cmd));
- }
- });
-
- return certbot.installPlugins(plugins)
- .then(() => {
- if (promises.length) {
- return Promise.all(promises)
- .then(() => {
- logger.info(`Added Certbot plugins ${plugins.join(', ')}`);
- });
- }
- });
- }
- });
-};
-
-
-/**
- * Starts a timer to call run the logrotation binary every two days
- * @returns {Promise}
- */
-const setupLogrotation = () => {
- const intervalTimeout = 1000 * 60 * 60 * 24 * 2; // 2 days
-
- const runLogrotate = async () => {
- try {
- await utils.exec('logrotate /etc/logrotate.d/nginx-proxy-manager');
- logger.info('Logrotate completed.');
- } catch (e) { logger.warn(e); }
- };
-
- logger.info('Logrotate Timer initialized');
- setInterval(runLogrotate, intervalTimeout);
- // And do this now as well
- return runLogrotate();
-};
-
-module.exports = () => setupDefaultUser()
- .then(setupDefaultSettings)
- .then(setupCertbotPlugins)
- .then(setupLogrotation);
diff --git a/backend/templates/_access.conf b/backend/templates/_access.conf
deleted file mode 100644
index f5926377..00000000
--- a/backend/templates/_access.conf
+++ /dev/null
@@ -1,25 +0,0 @@
-{% if access_list_id > 0 %}
- {% if access_list.items.length > 0 %}
- # Authorization
- auth_basic "Authorization required";
- auth_basic_user_file /data/access/{{ access_list_id }};
-
- {% if access_list.pass_auth == 0 or access_list.pass_auth == true %}
- proxy_set_header Authorization "";
- {% endif %}
-
- {% endif %}
-
- # Access Rules: {{ access_list.clients | size }} total
- {% for client in access_list.clients %}
- {{client | nginxAccessRule}}
- {% endfor %}
- deny all;
-
- # Access checks must...
- {% if access_list.satisfy_any == 1 or access_list.satisfy_any == true %}
- satisfy any;
- {% else %}
- satisfy all;
- {% endif %}
-{% endif %}
diff --git a/backend/templates/_assets.conf b/backend/templates/_assets.conf
deleted file mode 100644
index dcb183c5..00000000
--- a/backend/templates/_assets.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-{% if caching_enabled == 1 or caching_enabled == true -%}
- # Asset Caching
- include conf.d/include/assets.conf;
-{% endif %}
\ No newline at end of file
diff --git a/backend/templates/_certificates.conf b/backend/templates/_certificates.conf
deleted file mode 100644
index efcca5cd..00000000
--- a/backend/templates/_certificates.conf
+++ /dev/null
@@ -1,15 +0,0 @@
-{% if certificate and certificate_id > 0 -%}
-{% if certificate.provider == "letsencrypt" %}
- # Let's Encrypt SSL
- include conf.d/include/letsencrypt-acme-challenge.conf;
- include conf.d/include/ssl-cache.conf;
- include conf.d/include/ssl-ciphers.conf;
- ssl_certificate /etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem;
-{% else %}
- # Custom SSL
- ssl_certificate /data/custom_ssl/npm-{{ certificate_id }}/fullchain.pem;
- ssl_certificate_key /data/custom_ssl/npm-{{ certificate_id }}/privkey.pem;
-{% endif %}
-{% endif %}
-
diff --git a/backend/templates/_certificates_stream.conf b/backend/templates/_certificates_stream.conf
deleted file mode 100644
index ba7812fd..00000000
--- a/backend/templates/_certificates_stream.conf
+++ /dev/null
@@ -1,13 +0,0 @@
-{% if certificate and certificate_id > 0 %}
-{% if certificate.provider == "letsencrypt" %}
- # Let's Encrypt SSL
- include conf.d/include/ssl-cache-stream.conf;
- include conf.d/include/ssl-ciphers.conf;
- ssl_certificate /etc/letsencrypt/live/npm-{{ certificate_id }}/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/npm-{{ certificate_id }}/privkey.pem;
-{%- else %}
- # Custom SSL
- ssl_certificate /data/custom_ssl/npm-{{ certificate_id }}/fullchain.pem;
- ssl_certificate_key /data/custom_ssl/npm-{{ certificate_id }}/privkey.pem;
-{%- endif -%}
-{%- endif -%}
diff --git a/backend/templates/_exploits.conf b/backend/templates/_exploits.conf
deleted file mode 100644
index 002970d5..00000000
--- a/backend/templates/_exploits.conf
+++ /dev/null
@@ -1,4 +0,0 @@
-{% if block_exploits == 1 or block_exploits == true %}
- # Block Exploits
- include conf.d/include/block-exploits.conf;
-{% endif %}
\ No newline at end of file
diff --git a/backend/templates/_forced_ssl.conf b/backend/templates/_forced_ssl.conf
deleted file mode 100644
index 7fade20c..00000000
--- a/backend/templates/_forced_ssl.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-{% if certificate and certificate_id > 0 -%}
-{% if ssl_forced == 1 or ssl_forced == true %}
- # Force SSL
- include conf.d/include/force-ssl.conf;
-{% endif %}
-{% endif %}
\ No newline at end of file
diff --git a/backend/templates/_header_comment.conf b/backend/templates/_header_comment.conf
deleted file mode 100644
index 8f996d34..00000000
--- a/backend/templates/_header_comment.conf
+++ /dev/null
@@ -1,3 +0,0 @@
-# ------------------------------------------------------------
-# {{ domain_names | join: ", " }}
-# ------------------------------------------------------------
\ No newline at end of file
diff --git a/backend/templates/_hsts.conf b/backend/templates/_hsts.conf
deleted file mode 100644
index 26c83ee8..00000000
--- a/backend/templates/_hsts.conf
+++ /dev/null
@@ -1,8 +0,0 @@
-{% if certificate and certificate_id > 0 -%}
-{% if ssl_forced == 1 or ssl_forced == true %}
-{% if hsts_enabled == 1 or hsts_enabled == true %}
- # HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
- add_header Strict-Transport-Security $hsts_header always;
-{% endif %}
-{% endif %}
-{% endif %}
diff --git a/backend/templates/_hsts_map.conf b/backend/templates/_hsts_map.conf
deleted file mode 100644
index 27dd1f8f..00000000
--- a/backend/templates/_hsts_map.conf
+++ /dev/null
@@ -1,3 +0,0 @@
-map $scheme $hsts_header {
- https "max-age=63072000;{% if hsts_subdomains == 1 or hsts_subdomains == true -%} includeSubDomains;{% endif %} preload";
-}
\ No newline at end of file
diff --git a/backend/templates/_listen.conf b/backend/templates/_listen.conf
deleted file mode 100644
index 34a808e6..00000000
--- a/backend/templates/_listen.conf
+++ /dev/null
@@ -1,20 +0,0 @@
- listen 80;
-{% if ipv6 -%}
- listen [::]:80;
-{% else -%}
- #listen [::]:80;
-{% endif %}
-{% if certificate -%}
- listen 443 ssl;
-{% if ipv6 -%}
- listen [::]:443 ssl;
-{% else -%}
- #listen [::]:443;
-{% endif %}
-{% endif %}
- server_name {{ domain_names | join: " " }};
-{% if http2_support == 1 or http2_support == true %}
- http2 on;
-{% else -%}
- http2 off;
-{% endif %}
\ No newline at end of file
diff --git a/backend/templates/_location.conf b/backend/templates/_location.conf
deleted file mode 100644
index a2ecb166..00000000
--- a/backend/templates/_location.conf
+++ /dev/null
@@ -1,24 +0,0 @@
- location {{ path }} {
- {{ advanced_config }}
-
- proxy_set_header Host $host;
- proxy_set_header X-Forwarded-Scheme $scheme;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Forwarded-For $remote_addr;
- proxy_set_header X-Real-IP $remote_addr;
-
- proxy_pass {{ forward_scheme }}://{{ forward_host }}:{{ forward_port }}{{ forward_path }};
-
- {% include "_access.conf" %}
- {% include "_assets.conf" %}
- {% include "_exploits.conf" %}
- {% include "_forced_ssl.conf" %}
- {% include "_hsts.conf" %}
-
- {% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $http_connection;
- proxy_http_version 1.1;
- {% endif %}
- }
-
diff --git a/backend/templates/dead_host.conf b/backend/templates/dead_host.conf
deleted file mode 100644
index 2e7d2a00..00000000
--- a/backend/templates/dead_host.conf
+++ /dev/null
@@ -1,28 +0,0 @@
-{% include "_header_comment.conf" %}
-
-{% if enabled %}
-
-{% include "_hsts_map.conf" %}
-
-server {
-{% include "_listen.conf" %}
-{% include "_certificates.conf" %}
-{% include "_hsts.conf" %}
-{% include "_forced_ssl.conf" %}
-
- access_log /data/logs/dead-host-{{ id }}_access.log standard;
- error_log /data/logs/dead-host-{{ id }}_error.log warn;
-
-{{ advanced_config }}
-
-{% if use_default_location %}
- location / {
-{% include "_hsts.conf" %}
- return 404;
- }
-{% endif %}
-
- # Custom
- include /data/nginx/custom/server_dead[.]conf;
-}
-{% endif %}
diff --git a/backend/templates/default.conf b/backend/templates/default.conf
deleted file mode 100644
index cc590f9d..00000000
--- a/backend/templates/default.conf
+++ /dev/null
@@ -1,46 +0,0 @@
-# ------------------------------------------------------------
-# Default Site
-# ------------------------------------------------------------
-{% if value == "congratulations" %}
-# Skipping output, congratulations page configration is baked in.
-{%- else %}
-server {
- listen 80 default;
-{% if ipv6 -%}
- listen [::]:80 default;
-{% else -%}
- #listen [::]:80 default;
-{% endif %}
- server_name default-host.localhost;
- access_log /data/logs/default-host_access.log combined;
- error_log /data/logs/default-host_error.log warn;
-{% include "_exploits.conf" %}
-
- include conf.d/include/letsencrypt-acme-challenge.conf;
-
-{%- if value == "404" %}
- location / {
- return 404;
- }
-{% endif %}
-
-{%- if value == "444" %}
- location / {
- return 444;
- }
-{% endif %}
-
-{%- if value == "redirect" %}
- location / {
- return 301 {{ meta.redirect }};
- }
-{%- endif %}
-
-{%- if value == "html" %}
- root /data/nginx/default_www;
- location / {
- try_files $uri /index.html;
- }
-{%- endif %}
-}
-{% endif %}
diff --git a/backend/templates/ip_ranges.conf b/backend/templates/ip_ranges.conf
deleted file mode 100644
index 8ede2bd9..00000000
--- a/backend/templates/ip_ranges.conf
+++ /dev/null
@@ -1,3 +0,0 @@
-{% for range in ip_ranges %}
-set_real_ip_from {{ range }};
-{% endfor %}
\ No newline at end of file
diff --git a/backend/templates/letsencrypt-request.conf b/backend/templates/letsencrypt-request.conf
deleted file mode 100644
index 676c8a60..00000000
--- a/backend/templates/letsencrypt-request.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-{% include "_header_comment.conf" %}
-
-server {
- listen 80;
-{% if ipv6 -%}
- listen [::]:80;
-{% endif %}
-
- server_name {{ domain_names | join: " " }};
-
- access_log /data/logs/letsencrypt-requests_access.log standard;
- error_log /data/logs/letsencrypt-requests_error.log warn;
-
- include conf.d/include/letsencrypt-acme-challenge.conf;
-
- location / {
- return 404;
- }
-}
diff --git a/backend/templates/proxy_host.conf b/backend/templates/proxy_host.conf
deleted file mode 100644
index d23ca46f..00000000
--- a/backend/templates/proxy_host.conf
+++ /dev/null
@@ -1,53 +0,0 @@
-{% include "_header_comment.conf" %}
-
-{% if enabled %}
-
-{% include "_hsts_map.conf" %}
-
-server {
- set $forward_scheme {{ forward_scheme }};
- set $server "{{ forward_host }}";
- set $port {{ forward_port }};
-
-{% include "_listen.conf" %}
-{% include "_certificates.conf" %}
-{% include "_assets.conf" %}
-{% include "_exploits.conf" %}
-{% include "_hsts.conf" %}
-{% include "_forced_ssl.conf" %}
-
-{% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
-proxy_set_header Upgrade $http_upgrade;
-proxy_set_header Connection $http_connection;
-proxy_http_version 1.1;
-{% endif %}
-
- access_log /data/logs/proxy-host-{{ id }}_access.log proxy;
- error_log /data/logs/proxy-host-{{ id }}_error.log warn;
-
-{{ advanced_config }}
-
-{{ locations }}
-
-{% if use_default_location %}
-
- location / {
-
-{% include "_access.conf" %}
-{% include "_hsts.conf" %}
-
- {% if allow_websocket_upgrade == 1 or allow_websocket_upgrade == true %}
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $http_connection;
- proxy_http_version 1.1;
- {% endif %}
-
- # Proxy!
- include conf.d/include/proxy.conf;
- }
-{% endif %}
-
- # Custom
- include /data/nginx/custom/server_proxy[.]conf;
-}
-{% endif %}
diff --git a/backend/templates/redirection_host.conf b/backend/templates/redirection_host.conf
deleted file mode 100644
index 7dd36079..00000000
--- a/backend/templates/redirection_host.conf
+++ /dev/null
@@ -1,35 +0,0 @@
-{% include "_header_comment.conf" %}
-
-{% if enabled %}
-
-{% include "_hsts_map.conf" %}
-
-server {
-{% include "_listen.conf" %}
-{% include "_certificates.conf" %}
-{% include "_assets.conf" %}
-{% include "_exploits.conf" %}
-{% include "_hsts.conf" %}
-{% include "_forced_ssl.conf" %}
-
- access_log /data/logs/redirection-host-{{ id }}_access.log standard;
- error_log /data/logs/redirection-host-{{ id }}_error.log warn;
-
-{{ advanced_config }}
-
-{% if use_default_location %}
- location / {
-{% include "_hsts.conf" %}
-
- {% if preserve_path == 1 or preserve_path == true %}
- return {{ forward_http_code }} {{ forward_scheme }}://{{ forward_domain_name }}$request_uri;
- {% else %}
- return {{ forward_http_code }} {{ forward_scheme }}://{{ forward_domain_name }};
- {% endif %}
- }
-{% endif %}
-
- # Custom
- include /data/nginx/custom/server_redirect[.]conf;
-}
-{% endif %}
diff --git a/backend/templates/stream.conf b/backend/templates/stream.conf
deleted file mode 100644
index 7333aaee..00000000
--- a/backend/templates/stream.conf
+++ /dev/null
@@ -1,33 +0,0 @@
-# ------------------------------------------------------------
-# {{ incoming_port }} TCP: {{ tcp_forwarding }} UDP: {{ udp_forwarding }}
-# ------------------------------------------------------------
-
-{% if enabled %}
-{% if tcp_forwarding == 1 or tcp_forwarding == true -%}
-server {
- listen {{ incoming_port }} {%- if certificate %} ssl {%- endif %};
- {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} {%- if certificate %} ssl {%- endif %};
-
- {%- include "_certificates_stream.conf" %}
-
- proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
-
- # Custom
- include /data/nginx/custom/server_stream[.]conf;
- include /data/nginx/custom/server_stream_tcp[.]conf;
-}
-{% endif %}
-
-{% if udp_forwarding == 1 or udp_forwarding == true -%}
-server {
- listen {{ incoming_port }} udp;
- {% unless ipv6 -%} # {%- endunless -%} listen [::]:{{ incoming_port }} udp;
-
- proxy_pass {{ forwarding_host }}:{{ forwarding_port }};
-
- # Custom
- include /data/nginx/custom/server_stream[.]conf;
- include /data/nginx/custom/server_stream_udp[.]conf;
-}
-{% endif %}
-{% endif %}
\ No newline at end of file
diff --git a/backend/validate-schema.js b/backend/validate-schema.js
deleted file mode 100644
index 71a05c81..00000000
--- a/backend/validate-schema.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const SwaggerParser = require('@apidevtools/swagger-parser');
-const chalk = require('chalk');
-const schema = require('./schema');
-const log = console.log;
-
-schema.getCompiledSchema().then(async (swaggerJSON) => {
- try {
- const api = await SwaggerParser.validate(swaggerJSON);
- console.log('API name: %s, Version: %s', api.info.title, api.info.version);
- log(chalk.green('❯ Schema is valid'));
- } catch (e) {
- console.error(e);
- log(chalk.red('❯', e.message), '\n');
- process.exit(1);
- }
-});
diff --git a/backend/yarn.lock b/backend/yarn.lock
deleted file mode 100644
index bae734b4..00000000
--- a/backend/yarn.lock
+++ /dev/null
@@ -1,3808 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@apidevtools/json-schema-ref-parser@9.0.6":
- version "9.0.6"
- resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz#5d9000a3ac1fd25404da886da6b266adcd99cf1c"
- integrity sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==
- dependencies:
- "@jsdevtools/ono" "^7.1.3"
- call-me-maybe "^1.0.1"
- js-yaml "^3.13.1"
-
-"@apidevtools/json-schema-ref-parser@^11.7.0":
- version "11.7.0"
- resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.0.tgz#228d72018a0e7cbee744b677eaa01a8968f302d9"
- integrity sha512-pRrmXMCwnmrkS3MLgAIW5dXRzeTv6GLjkjb4HmxNnvAKXN1Nfzp4KmGADBQvlVUcqi+a5D+hfGDLLnd5NnYxog==
- dependencies:
- "@jsdevtools/ono" "^7.1.3"
- "@types/json-schema" "^7.0.15"
- js-yaml "^4.1.0"
-
-"@apidevtools/openapi-schemas@^2.1.0":
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17"
- integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==
-
-"@apidevtools/swagger-methods@^3.0.2":
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267"
- integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==
-
-"@apidevtools/swagger-parser@^10.1.0":
- version "10.1.0"
- resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.1.0.tgz#a987d71e5be61feb623203be0c96e5985b192ab6"
- integrity sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw==
- dependencies:
- "@apidevtools/json-schema-ref-parser" "9.0.6"
- "@apidevtools/openapi-schemas" "^2.1.0"
- "@apidevtools/swagger-methods" "^3.0.2"
- "@jsdevtools/ono" "^7.1.3"
- ajv "^8.6.3"
- ajv-draft-04 "^1.0.0"
- call-me-maybe "^1.0.1"
-
-"@eslint-community/eslint-utils@^4.2.0":
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz#a556790523a351b4e47e9d385f47265eaaf9780a"
- integrity sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==
- dependencies:
- eslint-visitor-keys "^3.3.0"
-
-"@eslint-community/regexpp@^4.4.0":
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.4.0.tgz#3e61c564fcd6b921cb789838631c5ee44df09403"
- integrity sha512-A9983Q0LnDGdLPjxyXQ00sbV+K+O+ko2Dr+CZigbHWtX9pNfxlaBkMR8X1CztI73zuEyEBXTVjx7CE+/VSwDiQ==
-
-"@eslint/eslintrc@^2.0.1":
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.1.tgz#7888fe7ec8f21bc26d646dbd2c11cd776e21192d"
- integrity sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==
- dependencies:
- ajv "^6.12.4"
- debug "^4.3.2"
- espree "^9.5.0"
- globals "^13.19.0"
- ignore "^5.2.0"
- import-fresh "^3.2.1"
- js-yaml "^4.1.0"
- minimatch "^3.1.2"
- strip-json-comments "^3.1.1"
-
-"@eslint/js@8.36.0":
- version "8.36.0"
- resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe"
- integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==
-
-"@gar/promisify@^1.0.1":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
- integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
-
-"@humanwhocodes/config-array@^0.11.8":
- version "0.11.8"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz#03595ac2075a4dc0f191cc2131de14fbd7d410b9"
- integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==
- dependencies:
- "@humanwhocodes/object-schema" "^1.2.1"
- debug "^4.1.1"
- minimatch "^3.0.5"
-
-"@humanwhocodes/module-importer@^1.0.1":
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
- integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
-
-"@humanwhocodes/object-schema@^1.2.1":
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
- integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
-
-"@jsdevtools/ono@^7.1.3":
- version "7.1.3"
- resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796"
- integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==
-
-"@mapbox/node-pre-gyp@^1.0.0":
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz#8e6735ccebbb1581e5a7e652244cadc8a844d03c"
- integrity sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==
- dependencies:
- detect-libc "^2.0.0"
- https-proxy-agent "^5.0.0"
- make-dir "^3.1.0"
- node-fetch "^2.6.7"
- nopt "^5.0.0"
- npmlog "^5.0.1"
- rimraf "^3.0.2"
- semver "^7.3.5"
- tar "^6.1.11"
-
-"@nodelib/fs.scandir@2.1.5":
- version "2.1.5"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
- integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
- dependencies:
- "@nodelib/fs.stat" "2.0.5"
- run-parallel "^1.1.9"
-
-"@nodelib/fs.stat@2.0.5":
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
- integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
-
-"@nodelib/fs.walk@^1.2.8":
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
- integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
- dependencies:
- "@nodelib/fs.scandir" "2.1.5"
- fastq "^1.6.0"
-
-"@npmcli/fs@^1.0.0":
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257"
- integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==
- dependencies:
- "@gar/promisify" "^1.0.1"
- semver "^7.3.5"
-
-"@npmcli/move-file@^1.0.1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674"
- integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==
- dependencies:
- mkdirp "^1.0.4"
- rimraf "^3.0.2"
-
-"@sindresorhus/is@^0.14.0":
- version "0.14.0"
- resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
- integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
-
-"@szmarczak/http-timer@^1.1.2":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
- integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
- dependencies:
- defer-to-connect "^1.0.1"
-
-"@tootallnate/once@1":
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
- integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
-
-"@types/color-name@^1.1.1":
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
- integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
-
-"@types/json-schema@^7.0.15":
- version "7.0.15"
- resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
- integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
-
-abbrev@1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
- integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
-
-accepts@~1.3.5, accepts@~1.3.8:
- version "1.3.8"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
- integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
- dependencies:
- mime-types "~2.1.34"
- negotiator "0.6.3"
-
-acorn-jsx@^5.3.2:
- version "5.3.2"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
- integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
-
-acorn@^8.8.0:
- version "8.8.2"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
- integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
-
-agent-base@6, agent-base@^6.0.2:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
- integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
- dependencies:
- debug "4"
-
-agentkeepalive@^4.1.3:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.3.0.tgz#bb999ff07412653c1803b3ced35e50729830a255"
- integrity sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==
- dependencies:
- debug "^4.1.0"
- depd "^2.0.0"
- humanize-ms "^1.2.1"
-
-aggregate-error@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
- integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
- dependencies:
- clean-stack "^2.0.0"
- indent-string "^4.0.0"
-
-ajv-draft-04@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8"
- integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==
-
-ajv@^6.10.0, ajv@^6.12.4:
- version "6.12.6"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
- integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
- dependencies:
- fast-deep-equal "^3.1.1"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.4.1"
- uri-js "^4.2.2"
-
-ajv@^8.17.1, ajv@^8.6.3:
- version "8.17.1"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6"
- integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==
- dependencies:
- fast-deep-equal "^3.1.3"
- fast-uri "^3.0.1"
- json-schema-traverse "^1.0.0"
- require-from-string "^2.0.2"
-
-ajv@^8.6.2:
- version "8.12.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1"
- integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
- dependencies:
- fast-deep-equal "^3.1.1"
- json-schema-traverse "^1.0.0"
- require-from-string "^2.0.2"
- uri-js "^4.2.2"
-
-ansi-align@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
- integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
- dependencies:
- string-width "^3.0.0"
-
-ansi-regex@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
- integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
-
-ansi-regex@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
- integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
-
-ansi-regex@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
- integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
-
-ansi-regex@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
- integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
-
-ansi-regex@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
- integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
-
-ansi-styles@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
- integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
- dependencies:
- color-convert "^1.9.0"
-
-ansi-styles@^4.0.0, ansi-styles@^4.1.0:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
- integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
- dependencies:
- "@types/color-name" "^1.1.1"
- color-convert "^2.0.1"
-
-anymatch@~3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
- integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
- dependencies:
- normalize-path "^3.0.0"
- picomatch "^2.0.4"
-
-aproba@^1.0.3:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
- integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
-
-"aproba@^1.0.3 || ^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc"
- integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==
-
-archiver-utils@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
- integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==
- dependencies:
- glob "^7.1.4"
- graceful-fs "^4.2.0"
- lazystream "^1.0.0"
- lodash.defaults "^4.2.0"
- lodash.difference "^4.5.0"
- lodash.flatten "^4.4.0"
- lodash.isplainobject "^4.0.6"
- lodash.union "^4.6.0"
- normalize-path "^3.0.0"
- readable-stream "^2.0.0"
-
-archiver@^5.3.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.0.tgz#dd3e097624481741df626267564f7dd8640a45ba"
- integrity sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==
- dependencies:
- archiver-utils "^2.1.0"
- async "^3.2.0"
- buffer-crc32 "^0.2.1"
- readable-stream "^3.6.0"
- readdir-glob "^1.0.0"
- tar-stream "^2.2.0"
- zip-stream "^4.1.0"
-
-are-we-there-yet@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c"
- integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==
- dependencies:
- delegates "^1.0.0"
- readable-stream "^3.6.0"
-
-are-we-there-yet@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd"
- integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==
- dependencies:
- delegates "^1.0.0"
- readable-stream "^3.6.0"
-
-are-we-there-yet@~1.1.2:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
- integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
- dependencies:
- delegates "^1.0.0"
- readable-stream "^2.0.6"
-
-argparse@^1.0.7:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
- integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
- dependencies:
- sprintf-js "~1.0.2"
-
-argparse@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
- integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
-
-array-flatten@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
- integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
-
-asn1@^0.2.4:
- version "0.2.4"
- resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
- integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
- dependencies:
- safer-buffer "~2.1.0"
-
-async@^3.2.0:
- version "3.2.4"
- resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
- integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
-
-aws-ssl-profiles@^1.1.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz#157dd77e9f19b1d123678e93f120e6f193022641"
- integrity sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==
-
-balanced-match@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
- integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
-
-base64-js@^1.3.1:
- version "1.5.1"
- resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
- integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
-
-batchflow@^0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/batchflow/-/batchflow-0.4.0.tgz#7d419df79b6b7587b06f9ea34f96ccef6f74e5b5"
- integrity sha1-fUGd95trdYewb56jT5bM72905bU=
-
-bcrypt@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-5.0.0.tgz#051407c7cd5ffbfb773d541ca3760ea0754e37e2"
- integrity sha512-jB0yCBl4W/kVHM2whjfyqnxTmOHkCX4kHEa5nYKSoGeYe8YrjTYTc87/6bwt1g8cmV0QrbhKriETg9jWtcREhg==
- dependencies:
- node-addon-api "^3.0.0"
- node-pre-gyp "0.15.0"
-
-binary-extensions@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
- integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
-
-bl@^4.0.3:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
- integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
- dependencies:
- buffer "^5.5.0"
- inherits "^2.0.4"
- readable-stream "^3.4.0"
-
-blueimp-md5@^2.16.0:
- version "2.17.0"
- resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.17.0.tgz#f4fcac088b115f7b4045f19f5da59e9d01b1bb96"
- integrity sha512-x5PKJHY5rHQYaADj6NwPUR2QRCUVSggPzrUKkeENpj871o9l9IefJbO2jkT5UvYykeOK9dx0VmkIo6dZ+vThYw==
-
-body-parser@1.20.3, body-parser@^1.20.3:
- version "1.20.3"
- resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
- integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
- dependencies:
- bytes "3.1.2"
- content-type "~1.0.5"
- debug "2.6.9"
- depd "2.0.0"
- destroy "1.2.0"
- http-errors "2.0.0"
- iconv-lite "0.4.24"
- on-finished "2.4.1"
- qs "6.13.0"
- raw-body "2.5.2"
- type-is "~1.6.18"
- unpipe "1.0.0"
-
-boxen@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
- integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==
- dependencies:
- ansi-align "^3.0.0"
- camelcase "^5.3.1"
- chalk "^3.0.0"
- cli-boxes "^2.2.0"
- string-width "^4.1.0"
- term-size "^2.1.0"
- type-fest "^0.8.1"
- widest-line "^3.1.0"
-
-brace-expansion@^1.1.7:
- version "1.1.12"
- resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843"
- integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==
- dependencies:
- balanced-match "^1.0.0"
- concat-map "0.0.1"
-
-braces@~3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
- integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
- dependencies:
- fill-range "^7.1.1"
-
-buffer-crc32@^0.2.1, buffer-crc32@^0.2.13:
- version "0.2.13"
- resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
- integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
-
-buffer-equal-constant-time@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
- integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=
-
-buffer@^5.5.0:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
- integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
- dependencies:
- base64-js "^1.3.1"
- ieee754 "^1.1.13"
-
-busboy@^0.3.1:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.3.1.tgz#170899274c5bf38aae27d5c62b71268cd585fd1b"
- integrity sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==
- dependencies:
- dicer "0.3.0"
-
-bytes@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
- integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
-
-bytes@3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
- integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
-
-cacache@^15.2.0:
- version "15.3.0"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb"
- integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==
- dependencies:
- "@npmcli/fs" "^1.0.0"
- "@npmcli/move-file" "^1.0.1"
- chownr "^2.0.0"
- fs-minipass "^2.0.0"
- glob "^7.1.4"
- infer-owner "^1.0.4"
- lru-cache "^6.0.0"
- minipass "^3.1.1"
- minipass-collect "^1.0.2"
- minipass-flush "^1.0.5"
- minipass-pipeline "^1.2.2"
- mkdirp "^1.0.3"
- p-map "^4.0.0"
- promise-inflight "^1.0.1"
- rimraf "^3.0.2"
- ssri "^8.0.1"
- tar "^6.0.2"
- unique-filename "^1.1.1"
-
-cacheable-request@^6.0.0:
- version "6.1.0"
- resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
- integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
- dependencies:
- clone-response "^1.0.2"
- get-stream "^5.1.0"
- http-cache-semantics "^4.0.0"
- keyv "^3.0.0"
- lowercase-keys "^2.0.0"
- normalize-url "^4.1.0"
- responselike "^1.0.2"
-
-call-bind@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
- integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
- dependencies:
- es-define-property "^1.0.0"
- es-errors "^1.3.0"
- function-bind "^1.1.2"
- get-intrinsic "^1.2.4"
- set-function-length "^1.2.1"
-
-call-me-maybe@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
- integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
-
-callsites@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
- integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-
-camelcase@^5.0.0, camelcase@^5.3.1:
- version "5.3.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
- integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
-
-chalk@4.1.2, chalk@^4.0.0:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
- integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-chalk@^2.3.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
- integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
- dependencies:
- ansi-styles "^3.2.1"
- escape-string-regexp "^1.0.5"
- supports-color "^5.3.0"
-
-chalk@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
- integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
-chokidar@^3.2.2:
- version "3.4.1"
- resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.1.tgz#e905bdecf10eaa0a0b1db0c664481cc4cbc22ba1"
- integrity sha512-TQTJyr2stihpC4Sya9hs2Xh+O2wf+igjL36Y75xx2WdHuiICcn/XJza46Jwt0eT5hVpQOzo3FpY3cj3RVYLX0g==
- dependencies:
- anymatch "~3.1.1"
- braces "~3.0.2"
- glob-parent "~5.1.0"
- is-binary-path "~2.1.0"
- is-glob "~4.0.1"
- normalize-path "~3.0.0"
- readdirp "~3.4.0"
- optionalDependencies:
- fsevents "~2.1.2"
-
-chownr@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
- integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
-
-chownr@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
- integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
-
-ci-info@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
- integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
-
-clean-stack@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
- integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
-
-cli-boxes@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d"
- integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==
-
-cliui@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
- integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
- dependencies:
- string-width "^4.2.0"
- strip-ansi "^6.0.0"
- wrap-ansi "^6.2.0"
-
-clone-response@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
- integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
- dependencies:
- mimic-response "^1.0.0"
-
-code-point-at@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
- integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
-
-color-convert@^1.9.0:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
- integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
- dependencies:
- color-name "1.1.3"
-
-color-convert@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
- integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
- dependencies:
- color-name "~1.1.4"
-
-color-name@1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
- integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
-
-color-name@~1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
- integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
-color-support@^1.1.2, color-support@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2"
- integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==
-
-colorette@2.0.19:
- version "2.0.19"
- resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
- integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
-
-commander@^10.0.0:
- version "10.0.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.0.tgz#71797971162cd3cf65f0b9d24eb28f8d303acdf1"
- integrity sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==
-
-commander@^9.1.0:
- version "9.5.0"
- resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30"
- integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==
-
-compress-commons@^4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d"
- integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==
- dependencies:
- buffer-crc32 "^0.2.13"
- crc32-stream "^4.0.2"
- normalize-path "^3.0.0"
- readable-stream "^3.6.0"
-
-compressible@~2.0.16:
- version "2.0.18"
- resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
- integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
- dependencies:
- mime-db ">= 1.43.0 < 2"
-
-compression@^1.7.4:
- version "1.7.4"
- resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
- integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
- dependencies:
- accepts "~1.3.5"
- bytes "3.0.0"
- compressible "~2.0.16"
- debug "2.6.9"
- on-headers "~1.0.2"
- safe-buffer "5.1.2"
- vary "~1.1.2"
-
-concat-map@0.0.1:
- version "0.0.1"
- resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
- integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
-
-configstore@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
- integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
- dependencies:
- dot-prop "^5.2.0"
- graceful-fs "^4.1.2"
- make-dir "^3.0.0"
- unique-string "^2.0.0"
- write-file-atomic "^3.0.0"
- xdg-basedir "^4.0.0"
-
-console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
- integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
-
-content-disposition@0.5.4:
- version "0.5.4"
- resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
- integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
- dependencies:
- safe-buffer "5.2.1"
-
-content-type@~1.0.4, content-type@~1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
- integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
-
-cookie-signature@1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
- integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
-
-cookie@0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
- integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
-
-core-util-is@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
- integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
-
-crc-32@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208"
- integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA==
- dependencies:
- exit-on-epipe "~1.0.1"
- printj "~1.1.0"
-
-crc32-stream@^4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007"
- integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==
- dependencies:
- crc-32 "^1.2.0"
- readable-stream "^3.4.0"
-
-cross-spawn@^7.0.2:
- version "7.0.6"
- resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
- integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
- dependencies:
- path-key "^3.1.0"
- shebang-command "^2.0.0"
- which "^2.0.1"
-
-crypto-random-string@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
- integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
-
-db-errors@^0.2.3:
- version "0.2.3"
- resolved "https://registry.yarnpkg.com/db-errors/-/db-errors-0.2.3.tgz#a6a38952e00b20e790f2695a6446b3c65497ffa2"
- integrity sha512-OOgqgDuCavHXjYSJoV2yGhv6SeG8nk42aoCSoyXLZUH7VwFG27rxbavU1z+VrZbZjphw5UkDQwUlD21MwZpUng==
-
-debug@2.6.9, debug@^2.2.0:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
- integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
- dependencies:
- ms "2.0.0"
-
-debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3:
- version "4.3.4"
- resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
- integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
- dependencies:
- ms "2.1.2"
-
-debug@^3.2.6:
- version "3.2.6"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
- integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
- dependencies:
- ms "^2.1.1"
-
-decamelize@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
- integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
-
-decompress-response@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
- integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
- dependencies:
- mimic-response "^1.0.0"
-
-deep-extend@^0.6.0:
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
- integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
-
-deep-is@^0.1.3:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
- integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
-
-defer-to-connect@^1.0.1:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
- integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
-
-define-data-property@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
- integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
- dependencies:
- es-define-property "^1.0.0"
- es-errors "^1.3.0"
- gopd "^1.0.1"
-
-delegates@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
- integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
-
-denque@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1"
- integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==
-
-depd@2.0.0, depd@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
- integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
-
-destroy@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
- integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
-
-detect-libc@^1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
- integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
-
-detect-libc@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd"
- integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
-
-dicer@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872"
- integrity sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==
- dependencies:
- streamsearch "0.1.2"
-
-doctrine@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
- integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
- dependencies:
- esutils "^2.0.2"
-
-dot-prop@^5.2.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb"
- integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==
- dependencies:
- is-obj "^2.0.0"
-
-duplexer3@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
- integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
-
-ecdsa-sig-formatter@1.0.11:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
- integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
- dependencies:
- safe-buffer "^5.0.1"
-
-ee-first@1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
- integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
-
-email-validator@^2.0.4:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed"
- integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ==
-
-emoji-regex@^7.0.1:
- version "7.0.3"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
- integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
-
-emoji-regex@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
- integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
-
-encodeurl@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
- integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
-
-encodeurl@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
- integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
-
-encoding@^0.1.12:
- version "0.1.13"
- resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
- integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
- dependencies:
- iconv-lite "^0.6.2"
-
-end-of-stream@^1.1.0, end-of-stream@^1.4.1:
- version "1.4.4"
- resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
- integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
- dependencies:
- once "^1.4.0"
-
-env-paths@^2.2.0:
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
- integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
-
-err-code@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
- integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
-
-error-ex@^1.3.1:
- version "1.3.2"
- resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
- integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
- dependencies:
- is-arrayish "^0.2.1"
-
-es-define-property@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
- integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
- dependencies:
- get-intrinsic "^1.2.4"
-
-es-errors@^1.3.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
- integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
-
-escalade@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
- integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
-escape-goat@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
- integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
-
-escape-html@~1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
- integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
-
-escape-string-regexp@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
- integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-
-escape-string-regexp@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
- integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
-
-eslint-plugin-align-assignments@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/eslint-plugin-align-assignments/-/eslint-plugin-align-assignments-1.1.2.tgz#83e1a8a826d4adf29e82b52d0bb39c88b301b576"
- integrity sha512-I1ZJgk9EjHfGVU9M2Ex8UkVkkjLL5Y9BS6VNnQHq79eHj2H4/Cgxf36lQSUTLgm2ntB03A2NtF+zg9fyi5vChg==
-
-eslint-scope@^7.1.1:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
- integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
- dependencies:
- esrecurse "^4.3.0"
- estraverse "^5.2.0"
-
-eslint-visitor-keys@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
- integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
-
-eslint@^8.36.0:
- version "8.36.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf"
- integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==
- dependencies:
- "@eslint-community/eslint-utils" "^4.2.0"
- "@eslint-community/regexpp" "^4.4.0"
- "@eslint/eslintrc" "^2.0.1"
- "@eslint/js" "8.36.0"
- "@humanwhocodes/config-array" "^0.11.8"
- "@humanwhocodes/module-importer" "^1.0.1"
- "@nodelib/fs.walk" "^1.2.8"
- ajv "^6.10.0"
- chalk "^4.0.0"
- cross-spawn "^7.0.2"
- debug "^4.3.2"
- doctrine "^3.0.0"
- escape-string-regexp "^4.0.0"
- eslint-scope "^7.1.1"
- eslint-visitor-keys "^3.3.0"
- espree "^9.5.0"
- esquery "^1.4.2"
- esutils "^2.0.2"
- fast-deep-equal "^3.1.3"
- file-entry-cache "^6.0.1"
- find-up "^5.0.0"
- glob-parent "^6.0.2"
- globals "^13.19.0"
- grapheme-splitter "^1.0.4"
- ignore "^5.2.0"
- import-fresh "^3.0.0"
- imurmurhash "^0.1.4"
- is-glob "^4.0.0"
- is-path-inside "^3.0.3"
- js-sdsl "^4.1.4"
- js-yaml "^4.1.0"
- json-stable-stringify-without-jsonify "^1.0.1"
- levn "^0.4.1"
- lodash.merge "^4.6.2"
- minimatch "^3.1.2"
- natural-compare "^1.4.0"
- optionator "^0.9.1"
- strip-ansi "^6.0.1"
- strip-json-comments "^3.1.0"
- text-table "^0.2.0"
-
-esm@^3.2.25:
- version "3.2.25"
- resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
- integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
-
-espree@^9.5.0:
- version "9.5.0"
- resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.0.tgz#3646d4e3f58907464edba852fa047e6a27bdf113"
- integrity sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==
- dependencies:
- acorn "^8.8.0"
- acorn-jsx "^5.3.2"
- eslint-visitor-keys "^3.3.0"
-
-esprima@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
- integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-
-esquery@^1.4.2:
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b"
- integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==
- dependencies:
- estraverse "^5.1.0"
-
-esrecurse@^4.3.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
- integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
- dependencies:
- estraverse "^5.2.0"
-
-estraverse@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
- integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
-
-estraverse@^5.2.0:
- version "5.3.0"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
- integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
-
-esutils@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
- integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
-
-etag@~1.8.1:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
- integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
-
-exit-on-epipe@~1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692"
- integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==
-
-express-fileupload@^1.1.9:
- version "1.1.9"
- resolved "https://registry.yarnpkg.com/express-fileupload/-/express-fileupload-1.1.9.tgz#e798e9318394ed5083e56217ad6cda576da465d2"
- integrity sha512-f2w0aoe7lj3NeD8a4MXmYQsqir3Z66I08l9AKq04QbFUAjeZNmPwTlR5Lx2NGwSu/PslsAjGC38MWzo5tTjoBg==
- dependencies:
- busboy "^0.3.1"
-
-express@^4.20.0:
- version "4.20.0"
- resolved "https://registry.yarnpkg.com/express/-/express-4.20.0.tgz#f1d08e591fcec770c07be4767af8eb9bcfd67c48"
- integrity sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==
- dependencies:
- accepts "~1.3.8"
- array-flatten "1.1.1"
- body-parser "1.20.3"
- content-disposition "0.5.4"
- content-type "~1.0.4"
- cookie "0.6.0"
- cookie-signature "1.0.6"
- debug "2.6.9"
- depd "2.0.0"
- encodeurl "~2.0.0"
- escape-html "~1.0.3"
- etag "~1.8.1"
- finalhandler "1.2.0"
- fresh "0.5.2"
- http-errors "2.0.0"
- merge-descriptors "1.0.3"
- methods "~1.1.2"
- on-finished "2.4.1"
- parseurl "~1.3.3"
- path-to-regexp "0.1.10"
- proxy-addr "~2.0.7"
- qs "6.11.0"
- range-parser "~1.2.1"
- safe-buffer "5.2.1"
- send "0.19.0"
- serve-static "1.16.0"
- setprototypeof "1.2.0"
- statuses "2.0.1"
- type-is "~1.6.18"
- utils-merge "1.0.1"
- vary "~1.1.2"
-
-fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
- integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-
-fast-json-stable-stringify@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
- integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
-
-fast-levenshtein@^2.0.6:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
- integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
-
-fast-uri@^3.0.1:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.2.tgz#d78b298cf70fd3b752fd951175a3da6a7b48f024"
- integrity sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row==
-
-fastq@^1.6.0:
- version "1.15.0"
- resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a"
- integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==
- dependencies:
- reusify "^1.0.4"
-
-figures@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
- integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
- dependencies:
- escape-string-regexp "^1.0.5"
-
-file-entry-cache@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
- integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
- dependencies:
- flat-cache "^3.0.4"
-
-fill-range@^7.1.1:
- version "7.1.1"
- resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
- integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
- dependencies:
- to-regex-range "^5.0.1"
-
-finalhandler@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
- integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
- dependencies:
- debug "2.6.9"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- on-finished "2.4.1"
- parseurl "~1.3.3"
- statuses "2.0.1"
- unpipe "~1.0.0"
-
-find-up@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
- integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
- dependencies:
- locate-path "^2.0.0"
-
-find-up@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
- integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
- dependencies:
- locate-path "^5.0.0"
- path-exists "^4.0.0"
-
-find-up@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
- integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
- dependencies:
- locate-path "^6.0.0"
- path-exists "^4.0.0"
-
-flat-cache@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
- integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==
- dependencies:
- flatted "^3.1.0"
- rimraf "^3.0.2"
-
-flatted@^3.1.0:
- version "3.2.7"
- resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
- integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
-
-forwarded@0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
- integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
-
-fresh@0.5.2:
- version "0.5.2"
- resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
- integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
-
-fs-constants@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
- integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
-
-fs-minipass@^1.2.7:
- version "1.2.7"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
- integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==
- dependencies:
- minipass "^2.6.0"
-
-fs-minipass@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
- integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
- dependencies:
- minipass "^3.0.0"
-
-fs.realpath@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
- integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
-
-fsevents@~2.1.2:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
- integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
-
-function-bind@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
- integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-
-function-bind@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
- integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
-
-gauge@^3.0.0:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395"
- integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==
- dependencies:
- aproba "^1.0.3 || ^2.0.0"
- color-support "^1.1.2"
- console-control-strings "^1.0.0"
- has-unicode "^2.0.1"
- object-assign "^4.1.1"
- signal-exit "^3.0.0"
- string-width "^4.2.3"
- strip-ansi "^6.0.1"
- wide-align "^1.1.2"
-
-gauge@^4.0.3:
- version "4.0.4"
- resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce"
- integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==
- dependencies:
- aproba "^1.0.3 || ^2.0.0"
- color-support "^1.1.3"
- console-control-strings "^1.1.0"
- has-unicode "^2.0.1"
- signal-exit "^3.0.7"
- string-width "^4.2.3"
- strip-ansi "^6.0.1"
- wide-align "^1.1.5"
-
-gauge@~2.7.3:
- version "2.7.4"
- resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
- integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
- dependencies:
- aproba "^1.0.3"
- console-control-strings "^1.0.0"
- has-unicode "^2.0.0"
- object-assign "^4.1.0"
- signal-exit "^3.0.0"
- string-width "^1.0.1"
- strip-ansi "^3.0.1"
- wide-align "^1.1.0"
-
-generate-function@^2.3.1:
- version "2.3.1"
- resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f"
- integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==
- dependencies:
- is-property "^1.0.2"
-
-get-caller-file@^2.0.1:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
- integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
-
-get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
- integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
- dependencies:
- es-errors "^1.3.0"
- function-bind "^1.1.2"
- has-proto "^1.0.1"
- has-symbols "^1.0.3"
- hasown "^2.0.0"
-
-get-package-type@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
- integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
-
-get-stream@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
- integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
- dependencies:
- pump "^3.0.0"
-
-get-stream@^5.1.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
- integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
- dependencies:
- pump "^3.0.0"
-
-getopts@2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4"
- integrity sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==
-
-glob-parent@^6.0.2:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
- integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
- dependencies:
- is-glob "^4.0.3"
-
-glob-parent@~5.1.0:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
- integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
- dependencies:
- is-glob "^4.0.1"
-
-glob@^7.1.3:
- version "7.1.6"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
- integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-glob@^7.1.4:
- version "7.1.7"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
- integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
- dependencies:
- fs.realpath "^1.0.0"
- inflight "^1.0.4"
- inherits "2"
- minimatch "^3.0.4"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
-global-dirs@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201"
- integrity sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==
- dependencies:
- ini "^1.3.5"
-
-globals@^13.19.0:
- version "13.20.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
- integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
- dependencies:
- type-fest "^0.20.2"
-
-gopd@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
- integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
- dependencies:
- get-intrinsic "^1.1.3"
-
-got@^9.6.0:
- version "9.6.0"
- resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
- integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
- dependencies:
- "@sindresorhus/is" "^0.14.0"
- "@szmarczak/http-timer" "^1.1.2"
- cacheable-request "^6.0.0"
- decompress-response "^3.3.0"
- duplexer3 "^0.1.4"
- get-stream "^4.1.0"
- lowercase-keys "^1.0.1"
- mimic-response "^1.0.1"
- p-cancelable "^1.0.0"
- to-readable-stream "^1.0.0"
- url-parse-lax "^3.0.0"
-
-graceful-fs@^4.1.15, graceful-fs@^4.1.2:
- version "4.2.4"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
- integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
-
-graceful-fs@^4.2.0:
- version "4.2.8"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
- integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
-
-graceful-fs@^4.2.6:
- version "4.2.11"
- resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
- integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
-
-grapheme-splitter@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
- integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
-
-gravatar@^1.8.0:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/gravatar/-/gravatar-1.8.1.tgz#743bbdf3185c3433172e00e0e6ff5f6b30c58997"
- integrity sha512-18frnfVp4kRYkM/eQW32Mfwlsh/KMbwd3S6nkescBZHioobflFEFHsvM71qZAkUSLNifyi2uoI+TuGxJAnQIOA==
- dependencies:
- blueimp-md5 "^2.16.0"
- email-validator "^2.0.4"
- querystring "0.2.0"
- yargs "^15.4.1"
-
-has-flag@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
- integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
-
-has-flag@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
- integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has-property-descriptors@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
- integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
- dependencies:
- es-define-property "^1.0.0"
-
-has-proto@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
- integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
-
-has-symbols@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
- integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
-
-has-unicode@^2.0.0, has-unicode@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
- integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
-
-has-yarn@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
- integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
-
-has@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
- integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
- dependencies:
- function-bind "^1.1.1"
-
-hasown@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
- integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
- dependencies:
- function-bind "^1.1.2"
-
-http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
- integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
-
-http-errors@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
- integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
- dependencies:
- depd "2.0.0"
- inherits "2.0.4"
- setprototypeof "1.2.0"
- statuses "2.0.1"
- toidentifier "1.0.1"
-
-http-proxy-agent@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
- integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==
- dependencies:
- "@tootallnate/once" "1"
- agent-base "6"
- debug "4"
-
-https-proxy-agent@^5.0.0:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
- integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
- dependencies:
- agent-base "6"
- debug "4"
-
-humanize-ms@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
- integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==
- dependencies:
- ms "^2.0.0"
-
-iconv-lite@0.4.24, iconv-lite@^0.4.4:
- version "0.4.24"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
- integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
- dependencies:
- safer-buffer ">= 2.1.2 < 3"
-
-iconv-lite@^0.6.2, iconv-lite@^0.6.3:
- version "0.6.3"
- resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
- integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
- dependencies:
- safer-buffer ">= 2.1.2 < 3.0.0"
-
-ieee754@^1.1.13:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
- integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-
-ignore-by-default@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
- integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
-
-ignore-walk@^3.0.1:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37"
- integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==
- dependencies:
- minimatch "^3.0.4"
-
-ignore@^5.2.0:
- version "5.2.4"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
- integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
-
-import-fresh@^3.0.0:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
- integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
- dependencies:
- parent-module "^1.0.0"
- resolve-from "^4.0.0"
-
-import-fresh@^3.2.1:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
- integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
- dependencies:
- parent-module "^1.0.0"
- resolve-from "^4.0.0"
-
-import-lazy@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
- integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
-
-imurmurhash@^0.1.4:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
- integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
-
-indent-string@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
- integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
-
-infer-owner@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
- integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
-
-inflight@^1.0.4:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
- integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
- dependencies:
- once "^1.3.0"
- wrappy "1"
-
-inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
- integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-
-inherits@2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
- integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
-ini@^1.3.5, ini@~1.3.0:
- version "1.3.8"
- resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
- integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
-
-interpret@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
- integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
-
-ip@^2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105"
- integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==
-
-ipaddr.js@1.9.1:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
- integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
-
-is-arrayish@^0.2.1:
- version "0.2.1"
- resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
- integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
-
-is-binary-path@~2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
- integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
- dependencies:
- binary-extensions "^2.0.0"
-
-is-ci@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
- integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==
- dependencies:
- ci-info "^2.0.0"
-
-is-core-module@^2.9.0:
- version "2.11.0"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
- integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
- dependencies:
- has "^1.0.3"
-
-is-extglob@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
- integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
-
-is-fullwidth-code-point@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
- integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
- dependencies:
- number-is-nan "^1.0.0"
-
-is-fullwidth-code-point@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
- integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
-
-is-fullwidth-code-point@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
- integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
-
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
- integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
- dependencies:
- is-extglob "^2.1.1"
-
-is-glob@^4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
- integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
- dependencies:
- is-extglob "^2.1.1"
-
-is-installed-globally@^0.3.1:
- version "0.3.2"
- resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
- integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==
- dependencies:
- global-dirs "^2.0.1"
- is-path-inside "^3.0.1"
-
-is-lambda@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5"
- integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==
-
-is-npm@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d"
- integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==
-
-is-number@^7.0.0:
- version "7.0.0"
- resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
- integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-
-is-obj@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
- integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
-
-is-path-inside@^3.0.1:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017"
- integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==
-
-is-path-inside@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
- integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
-
-is-property@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
- integrity sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==
-
-is-stream@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
- integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
-
-is-typedarray@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
- integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
-
-is-yarn-global@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
- integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
-
-isarray@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
- integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
-
-isexe@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
- integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-
-js-sdsl@^4.1.4:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711"
- integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==
-
-js-yaml@^3.13.1:
- version "3.14.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
- integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
- dependencies:
- argparse "^1.0.7"
- esprima "^4.0.0"
-
-js-yaml@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
- integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
- dependencies:
- argparse "^2.0.1"
-
-json-buffer@3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
- integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
-
-json-parse-better-errors@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
- integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
-
-json-schema-traverse@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
- integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
-
-json-schema-traverse@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
- integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
-
-json-stable-stringify-without-jsonify@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
- integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
-
-jsonwebtoken@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d"
- integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==
- dependencies:
- jws "^3.2.2"
- lodash "^4.17.21"
- ms "^2.1.1"
- semver "^7.3.8"
-
-jwa@^1.4.1:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
- integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
- dependencies:
- buffer-equal-constant-time "1.0.1"
- ecdsa-sig-formatter "1.0.11"
- safe-buffer "^5.0.1"
-
-jws@^3.2.2:
- version "3.2.2"
- resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
- integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
- dependencies:
- jwa "^1.4.1"
- safe-buffer "^5.0.1"
-
-keyv@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
- integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
- dependencies:
- json-buffer "3.0.0"
-
-knex@2.4.2:
- version "2.4.2"
- resolved "https://registry.yarnpkg.com/knex/-/knex-2.4.2.tgz#a34a289d38406dc19a0447a78eeaf2d16ebedd61"
- integrity sha512-tMI1M7a+xwHhPxjbl/H9K1kHX+VncEYcvCx5K00M16bWvpYPKAZd6QrCu68PtHAdIZNQPWZn0GVhqVBEthGWCg==
- dependencies:
- colorette "2.0.19"
- commander "^9.1.0"
- debug "4.3.4"
- escalade "^3.1.1"
- esm "^3.2.25"
- get-package-type "^0.1.0"
- getopts "2.3.0"
- interpret "^2.2.0"
- lodash "^4.17.21"
- pg-connection-string "2.5.0"
- rechoir "^0.8.0"
- resolve-from "^5.0.0"
- tarn "^3.0.2"
- tildify "2.0.0"
-
-latest-version@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
- integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
- dependencies:
- package-json "^6.3.0"
-
-lazystream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
- integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
- dependencies:
- readable-stream "^2.0.5"
-
-levn@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
- integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
- dependencies:
- prelude-ls "^1.2.1"
- type-check "~0.4.0"
-
-liquidjs@10.6.1:
- version "10.6.1"
- resolved "https://registry.yarnpkg.com/liquidjs/-/liquidjs-10.6.1.tgz#b401662cb8f0cca59b42f79fc08e411c86d92dab"
- integrity sha512-6yUDD8i6QRgVppB8dD73Z672lNa2pxHMsMNEZvbVQyj937wMk/kbKfhSnN9Sess/k8eRdgKeQHsTGIiCGkWrGw==
- dependencies:
- commander "^10.0.0"
-
-load-json-file@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
- integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^4.0.0"
- pify "^3.0.0"
- strip-bom "^3.0.0"
-
-locate-path@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
- integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
- dependencies:
- p-locate "^2.0.0"
- path-exists "^3.0.0"
-
-locate-path@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
- integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
- dependencies:
- p-locate "^4.1.0"
-
-locate-path@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
- integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
- dependencies:
- p-locate "^5.0.0"
-
-lodash.defaults@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
- integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
-
-lodash.difference@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
- integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=
-
-lodash.flatten@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
- integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
-
-lodash.isplainobject@^4.0.6:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
- integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
-
-lodash.merge@^4.6.2:
- version "4.6.2"
- resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
- integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-
-lodash.union@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
- integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
-
-lodash@^4.17.21:
- version "4.17.21"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
- integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-long@^5.2.1:
- version "5.2.3"
- resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1"
- integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==
-
-lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
- integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
-
-lowercase-keys@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
- integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
-
-lru-cache@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
- integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
- dependencies:
- yallist "^4.0.0"
-
-lru-cache@^7.14.1:
- version "7.18.3"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89"
- integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==
-
-lru-cache@^8.0.0:
- version "8.0.5"
- resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-8.0.5.tgz#983fe337f3e176667f8e567cfcce7cb064ea214e"
- integrity sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==
-
-make-dir@^3.0.0, make-dir@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
- integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
- dependencies:
- semver "^6.0.0"
-
-make-fetch-happen@^9.1.0:
- version "9.1.0"
- resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968"
- integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==
- dependencies:
- agentkeepalive "^4.1.3"
- cacache "^15.2.0"
- http-cache-semantics "^4.1.0"
- http-proxy-agent "^4.0.1"
- https-proxy-agent "^5.0.0"
- is-lambda "^1.0.1"
- lru-cache "^6.0.0"
- minipass "^3.1.3"
- minipass-collect "^1.0.2"
- minipass-fetch "^1.3.2"
- minipass-flush "^1.0.5"
- minipass-pipeline "^1.2.4"
- negotiator "^0.6.2"
- promise-retry "^2.0.1"
- socks-proxy-agent "^6.0.0"
- ssri "^8.0.0"
-
-media-typer@0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
- integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
-
-merge-descriptors@1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
- integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
-
-methods@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
- integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
-
-mime-db@1.44.0, "mime-db@>= 1.43.0 < 2":
- version "1.44.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92"
- integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==
-
-mime-db@1.52.0:
- version "1.52.0"
- resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
- integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
-
-mime-types@~2.1.24:
- version "2.1.27"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
- integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
- dependencies:
- mime-db "1.44.0"
-
-mime-types@~2.1.34:
- version "2.1.35"
- resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
- integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
- dependencies:
- mime-db "1.52.0"
-
-mime@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
- integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-
-mimic-response@^1.0.0, mimic-response@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
- integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
-
-minimatch@^3.0.4:
- version "3.0.4"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
- integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
- dependencies:
- brace-expansion "^1.1.7"
-
-minimatch@^3.0.5, minimatch@^3.1.2:
- version "3.1.2"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
- integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
- dependencies:
- brace-expansion "^1.1.7"
-
-minimist@^1.2.0, minimist@^1.2.5:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
- integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
-
-minipass-collect@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617"
- integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==
- dependencies:
- minipass "^3.0.0"
-
-minipass-fetch@^1.3.2:
- version "1.4.1"
- resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6"
- integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==
- dependencies:
- minipass "^3.1.0"
- minipass-sized "^1.0.3"
- minizlib "^2.0.0"
- optionalDependencies:
- encoding "^0.1.12"
-
-minipass-flush@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373"
- integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==
- dependencies:
- minipass "^3.0.0"
-
-minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c"
- integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==
- dependencies:
- minipass "^3.0.0"
-
-minipass-sized@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70"
- integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==
- dependencies:
- minipass "^3.0.0"
-
-minipass@^2.6.0, minipass@^2.9.0:
- version "2.9.0"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
- integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==
- dependencies:
- safe-buffer "^5.1.2"
- yallist "^3.0.0"
-
-minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3:
- version "3.3.6"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
- integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
- dependencies:
- yallist "^4.0.0"
-
-minipass@^4.0.0:
- version "4.2.5"
- resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.5.tgz#9e0e5256f1e3513f8c34691dd68549e85b2c8ceb"
- integrity sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==
-
-minizlib@^1.3.3:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
- integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==
- dependencies:
- minipass "^2.9.0"
-
-minizlib@^2.0.0, minizlib@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
- integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
- dependencies:
- minipass "^3.0.0"
- yallist "^4.0.0"
-
-mkdirp@^0.5.3, mkdirp@^0.5.5:
- version "0.5.5"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
- integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
- dependencies:
- minimist "^1.2.5"
-
-mkdirp@^1.0.3, mkdirp@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
- integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-
-moment@^2.29.4:
- version "2.29.4"
- resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
- integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
-
-ms@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
- integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
-
-ms@2.1.2, ms@^2.1.1:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
- integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-
-ms@2.1.3, ms@^2.0.0:
- version "2.1.3"
- resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
- integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-
-mysql2@^3.11.1:
- version "3.11.1"
- resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-3.11.1.tgz#edfb856e2176fcf43d2cc066dd4959e9fc76ea85"
- integrity sha512-Oc8Zffd0gpIJnJ/NOMp6IiiJJDdWc7nmWpS+UE3K9feTpYia8XkbgL6EaOJYz52f6+2pAoC0eAQqUzal4lnNGQ==
- dependencies:
- aws-ssl-profiles "^1.1.1"
- denque "^2.1.0"
- generate-function "^2.3.1"
- iconv-lite "^0.6.3"
- long "^5.2.1"
- lru-cache "^8.0.0"
- named-placeholders "^1.1.3"
- seq-queue "^0.0.5"
- sqlstring "^2.3.2"
-
-named-placeholders@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.3.tgz#df595799a36654da55dda6152ba7a137ad1d9351"
- integrity sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==
- dependencies:
- lru-cache "^7.14.1"
-
-natural-compare@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
- integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
-
-needle@^2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/needle/-/needle-2.5.0.tgz#e6fc4b3cc6c25caed7554bd613a5cf0bac8c31c0"
- integrity sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==
- dependencies:
- debug "^3.2.6"
- iconv-lite "^0.4.4"
- sax "^1.2.4"
-
-negotiator@0.6.3, negotiator@^0.6.2:
- version "0.6.3"
- resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
- integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
-
-node-addon-api@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.0.0.tgz#812446a1001a54f71663bed188314bba07e09247"
- integrity sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg==
-
-node-addon-api@^4.2.0:
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f"
- integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==
-
-node-fetch@^2.6.7:
- version "2.6.9"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6"
- integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==
- dependencies:
- whatwg-url "^5.0.0"
-
-node-gyp@8.x:
- version "8.4.1"
- resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937"
- integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==
- dependencies:
- env-paths "^2.2.0"
- glob "^7.1.4"
- graceful-fs "^4.2.6"
- make-fetch-happen "^9.1.0"
- nopt "^5.0.0"
- npmlog "^6.0.0"
- rimraf "^3.0.2"
- semver "^7.3.5"
- tar "^6.1.2"
- which "^2.0.2"
-
-node-pre-gyp@0.15.0:
- version "0.15.0"
- resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz#c2fc383276b74c7ffa842925241553e8b40f1087"
- integrity sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==
- dependencies:
- detect-libc "^1.0.2"
- mkdirp "^0.5.3"
- needle "^2.5.0"
- nopt "^4.0.1"
- npm-packlist "^1.1.6"
- npmlog "^4.0.2"
- rc "^1.2.7"
- rimraf "^2.6.1"
- semver "^5.3.0"
- tar "^4.4.2"
-
-node-rsa@^1.0.8:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.1.1.tgz#efd9ad382097782f506153398496f79e4464434d"
- integrity sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==
- dependencies:
- asn1 "^0.2.4"
-
-nodemon@^2.0.2:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416"
- integrity sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==
- dependencies:
- chokidar "^3.2.2"
- debug "^3.2.6"
- ignore-by-default "^1.0.1"
- minimatch "^3.0.4"
- pstree.remy "^1.1.7"
- semver "^5.7.1"
- supports-color "^5.5.0"
- touch "^3.1.0"
- undefsafe "^2.0.2"
- update-notifier "^4.0.0"
-
-nopt@^4.0.1:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
- integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==
- dependencies:
- abbrev "1"
- osenv "^0.1.4"
-
-nopt@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
- integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
- dependencies:
- abbrev "1"
-
-nopt@~1.0.10:
- version "1.0.10"
- resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
- integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=
- dependencies:
- abbrev "1"
-
-normalize-path@^3.0.0, normalize-path@~3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
- integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
-
-normalize-url@^4.1.0:
- version "4.5.1"
- resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a"
- integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==
-
-npm-bundled@^1.0.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b"
- integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==
- dependencies:
- npm-normalize-package-bin "^1.0.1"
-
-npm-normalize-package-bin@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2"
- integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==
-
-npm-packlist@^1.1.6:
- version "1.4.8"
- resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e"
- integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==
- dependencies:
- ignore-walk "^3.0.1"
- npm-bundled "^1.0.1"
- npm-normalize-package-bin "^1.0.1"
-
-npmlog@^4.0.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
- integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
- dependencies:
- are-we-there-yet "~1.1.2"
- console-control-strings "~1.1.0"
- gauge "~2.7.3"
- set-blocking "~2.0.0"
-
-npmlog@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0"
- integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==
- dependencies:
- are-we-there-yet "^2.0.0"
- console-control-strings "^1.1.0"
- gauge "^3.0.0"
- set-blocking "^2.0.0"
-
-npmlog@^6.0.0:
- version "6.0.2"
- resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830"
- integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==
- dependencies:
- are-we-there-yet "^3.0.0"
- console-control-strings "^1.1.0"
- gauge "^4.0.3"
- set-blocking "^2.0.0"
-
-number-is-nan@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
- integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
-
-object-assign@^4.1.0, object-assign@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
- integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
-
-object-inspect@^1.13.1:
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
- integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
-
-objection@3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/objection/-/objection-3.0.1.tgz#f67dc698187d10524e5d1b5d37a54e5bba49a42a"
- integrity sha512-rqNnyQE+C55UHjdpTOJEKQHJGZ/BGtBBtgxdUpKG4DQXRUmqxfmgS/MhPWxB9Pw0mLSVLEltr6soD4c0Sddy0Q==
- dependencies:
- ajv "^8.6.2"
- db-errors "^0.2.3"
-
-on-finished@2.4.1:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
- integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
- dependencies:
- ee-first "1.1.1"
-
-on-headers@~1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
- integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
-
-once@^1.3.0, once@^1.3.1, once@^1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
- integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
- dependencies:
- wrappy "1"
-
-optionator@^0.9.1:
- version "0.9.1"
- resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
- integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
- dependencies:
- deep-is "^0.1.3"
- fast-levenshtein "^2.0.6"
- levn "^0.4.1"
- prelude-ls "^1.2.1"
- type-check "^0.4.0"
- word-wrap "^1.2.3"
-
-os-homedir@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
- integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-
-os-tmpdir@^1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
- integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-
-osenv@^0.1.4:
- version "0.1.5"
- resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
- integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
- dependencies:
- os-homedir "^1.0.0"
- os-tmpdir "^1.0.0"
-
-p-cancelable@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
- integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
-
-p-limit@^1.1.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
- integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
- dependencies:
- p-try "^1.0.0"
-
-p-limit@^2.2.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
- integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
- dependencies:
- p-try "^2.0.0"
-
-p-limit@^3.0.2:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
- integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
- dependencies:
- yocto-queue "^0.1.0"
-
-p-locate@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
- integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
- dependencies:
- p-limit "^1.1.0"
-
-p-locate@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
- integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
- dependencies:
- p-limit "^2.2.0"
-
-p-locate@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
- integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
- dependencies:
- p-limit "^3.0.2"
-
-p-map@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
- integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
- dependencies:
- aggregate-error "^3.0.0"
-
-p-try@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
- integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
-
-p-try@^2.0.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
- integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-
-package-json@^6.3.0:
- version "6.5.0"
- resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0"
- integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
- dependencies:
- got "^9.6.0"
- registry-auth-token "^4.0.0"
- registry-url "^5.0.0"
- semver "^6.2.0"
-
-parent-module@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
- integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
- dependencies:
- callsites "^3.0.0"
-
-parse-json@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
- integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
- dependencies:
- error-ex "^1.3.1"
- json-parse-better-errors "^1.0.1"
-
-parseurl@~1.3.3:
- version "1.3.3"
- resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
- integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
-
-path-exists@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
- integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
-
-path-exists@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
- integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
-
-path-is-absolute@^1.0.0:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
- integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-
-path-key@^3.1.0:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
- integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-
-path-parse@^1.0.7:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
- integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-
-path-to-regexp@0.1.10:
- version "0.1.10"
- resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b"
- integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==
-
-path@^0.12.7:
- version "0.12.7"
- resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
- integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=
- dependencies:
- process "^0.11.1"
- util "^0.10.3"
-
-pg-cloudflare@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98"
- integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==
-
-pg-connection-string@2.5.0:
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34"
- integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==
-
-pg-connection-string@^2.7.0:
- version "2.7.0"
- resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.7.0.tgz#f1d3489e427c62ece022dba98d5262efcb168b37"
- integrity sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==
-
-pg-int8@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
- integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
-
-pg-pool@^3.7.0:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.7.0.tgz#d4d3c7ad640f8c6a2245adc369bafde4ebb8cbec"
- integrity sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==
-
-pg-protocol@^1.7.0:
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.7.0.tgz#ec037c87c20515372692edac8b63cf4405448a93"
- integrity sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==
-
-pg-types@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3"
- integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==
- dependencies:
- pg-int8 "1.0.1"
- postgres-array "~2.0.0"
- postgres-bytea "~1.0.0"
- postgres-date "~1.0.4"
- postgres-interval "^1.1.0"
-
-pg@^8.13.1:
- version "8.13.1"
- resolved "https://registry.yarnpkg.com/pg/-/pg-8.13.1.tgz#6498d8b0a87ff76c2df7a32160309d3168c0c080"
- integrity sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==
- dependencies:
- pg-connection-string "^2.7.0"
- pg-pool "^3.7.0"
- pg-protocol "^1.7.0"
- pg-types "^2.1.0"
- pgpass "1.x"
- optionalDependencies:
- pg-cloudflare "^1.1.1"
-
-pgpass@1.x:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d"
- integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==
- dependencies:
- split2 "^4.1.0"
-
-picomatch@^2.0.4, picomatch@^2.2.1:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
- integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
-
-pify@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
- integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
-
-pkg-conf@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058"
- integrity sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=
- dependencies:
- find-up "^2.0.0"
- load-json-file "^4.0.0"
-
-postgres-array@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e"
- integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==
-
-postgres-bytea@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35"
- integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==
-
-postgres-date@~1.0.4:
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8"
- integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==
-
-postgres-interval@^1.1.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695"
- integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==
- dependencies:
- xtend "^4.0.0"
-
-prelude-ls@^1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
- integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
-
-prepend-http@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
- integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
-
-prettier@^2.0.4:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
- integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
-
-printj@~1.1.0:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
- integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ==
-
-process-nextick-args@~2.0.0:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
- integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
-
-process@^0.11.1:
- version "0.11.10"
- resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
- integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
-
-promise-inflight@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
- integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==
-
-promise-retry@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
- integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
- dependencies:
- err-code "^2.0.2"
- retry "^0.12.0"
-
-proxy-addr@~2.0.7:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
- integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
- dependencies:
- forwarded "0.2.0"
- ipaddr.js "1.9.1"
-
-pstree.remy@^1.1.7:
- version "1.1.8"
- resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
- integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
-
-pump@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
- integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
- dependencies:
- end-of-stream "^1.1.0"
- once "^1.3.1"
-
-punycode@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
- integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-
-pupa@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.0.1.tgz#dbdc9ff48ffbea4a26a069b6f9f7abb051008726"
- integrity sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==
- dependencies:
- escape-goat "^2.0.0"
-
-qs@6.11.0:
- version "6.11.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
- integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
- dependencies:
- side-channel "^1.0.4"
-
-qs@6.13.0:
- version "6.13.0"
- resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
- integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
- dependencies:
- side-channel "^1.0.6"
-
-querystring@0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
- integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
-
-queue-microtask@^1.2.2:
- version "1.2.3"
- resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
- integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
-
-range-parser@~1.2.1:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
- integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
-
-raw-body@2.5.2:
- version "2.5.2"
- resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
- integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
- dependencies:
- bytes "3.1.2"
- http-errors "2.0.0"
- iconv-lite "0.4.24"
- unpipe "1.0.0"
-
-rc@^1.2.7, rc@^1.2.8:
- version "1.2.8"
- resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
- integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
- dependencies:
- deep-extend "^0.6.0"
- ini "~1.3.0"
- minimist "^1.2.0"
- strip-json-comments "~2.0.1"
-
-readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6:
- version "2.3.7"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
- integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
- dependencies:
- core-util-is "~1.0.0"
- inherits "~2.0.3"
- isarray "~1.0.0"
- process-nextick-args "~2.0.0"
- safe-buffer "~5.1.1"
- string_decoder "~1.1.1"
- util-deprecate "~1.0.1"
-
-readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
- integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
- dependencies:
- inherits "^2.0.3"
- string_decoder "^1.1.1"
- util-deprecate "^1.0.1"
-
-readdir-glob@^1.0.0:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4"
- integrity sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==
- dependencies:
- minimatch "^3.0.4"
-
-readdirp@~3.4.0:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada"
- integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==
- dependencies:
- picomatch "^2.2.1"
-
-rechoir@^0.8.0:
- version "0.8.0"
- resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22"
- integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==
- dependencies:
- resolve "^1.20.0"
-
-registry-auth-token@^4.0.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.0.tgz#1d37dffda72bbecd0f581e4715540213a65eb7da"
- integrity sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==
- dependencies:
- rc "^1.2.8"
-
-registry-url@^5.0.0:
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
- integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
- dependencies:
- rc "^1.2.8"
-
-require-directory@^2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
- integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
-
-require-from-string@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
- integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
-
-require-main-filename@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
- integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
-
-resolve-from@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
- integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-
-resolve-from@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
- integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
-
-resolve@^1.20.0:
- version "1.22.1"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
- integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
- dependencies:
- is-core-module "^2.9.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
-responselike@^1.0.2:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
- integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
- dependencies:
- lowercase-keys "^1.0.0"
-
-retry@^0.12.0:
- version "0.12.0"
- resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
- integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==
-
-reusify@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
- integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
-
-rimraf@^2.6.1:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
- integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
- dependencies:
- glob "^7.1.3"
-
-rimraf@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
- integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
- dependencies:
- glob "^7.1.3"
-
-run-parallel@^1.1.9:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
- integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
- dependencies:
- queue-microtask "^1.2.2"
-
-safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
- integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
- integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
-
-"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@~2.1.0:
- version "2.1.2"
- resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
- integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-
-sax@^1.2.4:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
- integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-
-semver-diff@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
- integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==
- dependencies:
- semver "^6.3.0"
-
-semver@^5.3.0, semver@^5.7.1:
- version "5.7.2"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
- integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
-
-semver@^6.0.0, semver@^6.2.0, semver@^6.3.0:
- version "6.3.1"
- resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
- integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
-
-semver@^7.3.5, semver@^7.3.8:
- version "7.5.4"
- resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
- integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
- dependencies:
- lru-cache "^6.0.0"
-
-send@0.18.0:
- version "0.18.0"
- resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
- integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
- dependencies:
- debug "2.6.9"
- depd "2.0.0"
- destroy "1.2.0"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- fresh "0.5.2"
- http-errors "2.0.0"
- mime "1.6.0"
- ms "2.1.3"
- on-finished "2.4.1"
- range-parser "~1.2.1"
- statuses "2.0.1"
-
-send@0.19.0:
- version "0.19.0"
- resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
- integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
- dependencies:
- debug "2.6.9"
- depd "2.0.0"
- destroy "1.2.0"
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- etag "~1.8.1"
- fresh "0.5.2"
- http-errors "2.0.0"
- mime "1.6.0"
- ms "2.1.3"
- on-finished "2.4.1"
- range-parser "~1.2.1"
- statuses "2.0.1"
-
-seq-queue@^0.0.5:
- version "0.0.5"
- resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e"
- integrity sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==
-
-serve-static@1.16.0:
- version "1.16.0"
- resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.0.tgz#2bf4ed49f8af311b519c46f272bf6ac3baf38a92"
- integrity sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==
- dependencies:
- encodeurl "~1.0.2"
- escape-html "~1.0.3"
- parseurl "~1.3.3"
- send "0.18.0"
-
-set-blocking@^2.0.0, set-blocking@~2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
- integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
-
-set-function-length@^1.2.1:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
- integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
- dependencies:
- define-data-property "^1.1.4"
- es-errors "^1.3.0"
- function-bind "^1.1.2"
- get-intrinsic "^1.2.4"
- gopd "^1.0.1"
- has-property-descriptors "^1.0.2"
-
-setprototypeof@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
- integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
-
-shebang-command@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
- integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
- dependencies:
- shebang-regex "^3.0.0"
-
-shebang-regex@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
- integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-
-side-channel@^1.0.4, side-channel@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
- integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
- dependencies:
- call-bind "^1.0.7"
- es-errors "^1.3.0"
- get-intrinsic "^1.2.4"
- object-inspect "^1.13.1"
-
-signal-exit@^3.0.0, signal-exit@^3.0.2:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
- integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
-
-signal-exit@^3.0.7:
- version "3.0.7"
- resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
- integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
-
-signale@1.4.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/signale/-/signale-1.4.0.tgz#c4be58302fb0262ac00fc3d886a7c113759042f1"
- integrity sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==
- dependencies:
- chalk "^2.3.2"
- figures "^2.0.0"
- pkg-conf "^2.1.0"
-
-smart-buffer@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
- integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
-
-socks-proxy-agent@^6.0.0:
- version "6.2.1"
- resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce"
- integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==
- dependencies:
- agent-base "^6.0.2"
- debug "^4.3.3"
- socks "^2.6.2"
-
-socks@^2.6.2:
- version "2.7.1"
- resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55"
- integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==
- dependencies:
- ip "^2.0.0"
- smart-buffer "^4.2.0"
-
-split2@^4.1.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
- integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
-
-sprintf-js@~1.0.2:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
- integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
-
-sqlite3@5.1.6:
- version "5.1.6"
- resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.6.tgz#1d4fbc90fe4fbd51e952e0a90fd8f6c2b9098e97"
- integrity sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==
- dependencies:
- "@mapbox/node-pre-gyp" "^1.0.0"
- node-addon-api "^4.2.0"
- tar "^6.1.11"
- optionalDependencies:
- node-gyp "8.x"
-
-sqlstring@^2.3.2:
- version "2.3.3"
- resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c"
- integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==
-
-ssri@^8.0.0, ssri@^8.0.1:
- version "8.0.1"
- resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af"
- integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==
- dependencies:
- minipass "^3.1.1"
-
-statuses@2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
- integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
-
-streamsearch@0.1.2:
- version "0.1.2"
- resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a"
- integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=
-
-string-width@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
- integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
- dependencies:
- code-point-at "^1.0.0"
- is-fullwidth-code-point "^1.0.0"
- strip-ansi "^3.0.0"
-
-"string-width@^1.0.2 || 2":
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
- integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
- dependencies:
- is-fullwidth-code-point "^2.0.0"
- strip-ansi "^4.0.0"
-
-"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3:
- version "4.2.3"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
-string-width@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
- integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
- dependencies:
- emoji-regex "^7.0.1"
- is-fullwidth-code-point "^2.0.0"
- strip-ansi "^5.1.0"
-
-string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
- integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.0"
-
-string_decoder@^1.1.1:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
- integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
- dependencies:
- safe-buffer "~5.2.0"
-
-string_decoder@~1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
- integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
- dependencies:
- safe-buffer "~5.1.0"
-
-strip-ansi@^3.0.0, strip-ansi@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
- integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
- dependencies:
- ansi-regex "^2.0.0"
-
-strip-ansi@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
- integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
- dependencies:
- ansi-regex "^3.0.0"
-
-strip-ansi@^5.1.0:
- version "5.2.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
- integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
- dependencies:
- ansi-regex "^4.1.0"
-
-strip-ansi@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
- integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
- dependencies:
- ansi-regex "^5.0.0"
-
-strip-ansi@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
-strip-bom@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
- integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
-
-strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
- integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-
-strip-json-comments@~2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
- integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
-
-supports-color@^5.3.0, supports-color@^5.5.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
- integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
- dependencies:
- has-flag "^3.0.0"
-
-supports-color@^7.1.0:
- version "7.1.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
- integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
- dependencies:
- has-flag "^4.0.0"
-
-supports-preserve-symlinks-flag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
- integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-
-tar-stream@^2.2.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
- integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
- dependencies:
- bl "^4.0.3"
- end-of-stream "^1.4.1"
- fs-constants "^1.0.0"
- inherits "^2.0.3"
- readable-stream "^3.1.1"
-
-tar@^4.4.2:
- version "4.4.19"
- resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3"
- integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==
- dependencies:
- chownr "^1.1.4"
- fs-minipass "^1.2.7"
- minipass "^2.9.0"
- minizlib "^1.3.3"
- mkdirp "^0.5.5"
- safe-buffer "^5.2.1"
- yallist "^3.1.1"
-
-tar@^6.0.2, tar@^6.1.11, tar@^6.1.2:
- version "6.1.13"
- resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.13.tgz#46e22529000f612180601a6fe0680e7da508847b"
- integrity sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==
- dependencies:
- chownr "^2.0.0"
- fs-minipass "^2.0.0"
- minipass "^4.0.0"
- minizlib "^2.1.1"
- mkdirp "^1.0.3"
- yallist "^4.0.0"
-
-tarn@^3.0.2:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693"
- integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==
-
-temp-dir@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d"
- integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=
-
-temp-write@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320"
- integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==
- dependencies:
- graceful-fs "^4.1.15"
- is-stream "^2.0.0"
- make-dir "^3.0.0"
- temp-dir "^1.0.0"
- uuid "^3.3.2"
-
-term-size@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753"
- integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==
-
-text-table@^0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
- integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
-
-tildify@2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/tildify/-/tildify-2.0.0.tgz#f205f3674d677ce698b7067a99e949ce03b4754a"
- integrity sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==
-
-to-readable-stream@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
- integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
-
-to-regex-range@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
- integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
- dependencies:
- is-number "^7.0.0"
-
-toidentifier@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
- integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
-
-touch@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
- integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
- dependencies:
- nopt "~1.0.10"
-
-tr46@~0.0.3:
- version "0.0.3"
- resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
- integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
-
-type-check@^0.4.0, type-check@~0.4.0:
- version "0.4.0"
- resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
- integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
- dependencies:
- prelude-ls "^1.2.1"
-
-type-fest@^0.20.2:
- version "0.20.2"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
- integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
-
-type-fest@^0.8.1:
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
- integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-
-type-is@~1.6.18:
- version "1.6.18"
- resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
- integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
- dependencies:
- media-typer "0.3.0"
- mime-types "~2.1.24"
-
-typedarray-to-buffer@^3.1.5:
- version "3.1.5"
- resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
- integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
- dependencies:
- is-typedarray "^1.0.0"
-
-undefsafe@^2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae"
- integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==
- dependencies:
- debug "^2.2.0"
-
-unique-filename@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
- integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==
- dependencies:
- unique-slug "^2.0.0"
-
-unique-slug@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c"
- integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==
- dependencies:
- imurmurhash "^0.1.4"
-
-unique-string@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
- integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
- dependencies:
- crypto-random-string "^2.0.0"
-
-unpipe@1.0.0, unpipe@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
- integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
-
-update-notifier@^4.0.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.0.tgz#4866b98c3bc5b5473c020b1250583628f9a328f3"
- integrity sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==
- dependencies:
- boxen "^4.2.0"
- chalk "^3.0.0"
- configstore "^5.0.1"
- has-yarn "^2.1.0"
- import-lazy "^2.1.0"
- is-ci "^2.0.0"
- is-installed-globally "^0.3.1"
- is-npm "^4.0.0"
- is-yarn-global "^0.3.0"
- latest-version "^5.0.0"
- pupa "^2.0.1"
- semver-diff "^3.1.1"
- xdg-basedir "^4.0.0"
-
-uri-js@^4.2.2:
- version "4.2.2"
- resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
- integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
- dependencies:
- punycode "^2.1.0"
-
-url-parse-lax@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
- integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
- dependencies:
- prepend-http "^2.0.0"
-
-util-deprecate@^1.0.1, util-deprecate@~1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
- integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-
-util@^0.10.3:
- version "0.10.4"
- resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
- integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
- dependencies:
- inherits "2.0.3"
-
-utils-merge@1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
- integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
-
-uuid@^3.3.2:
- version "3.4.0"
- resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
- integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-
-vary@~1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
- integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
-
-webidl-conversions@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
- integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
-
-whatwg-url@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
- integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
- dependencies:
- tr46 "~0.0.3"
- webidl-conversions "^3.0.0"
-
-which-module@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
- integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-
-which@^2.0.1, which@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
- integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
- dependencies:
- isexe "^2.0.0"
-
-wide-align@^1.1.0:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
- integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
- dependencies:
- string-width "^1.0.2 || 2"
-
-wide-align@^1.1.2, wide-align@^1.1.5:
- version "1.1.5"
- resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
- integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
- dependencies:
- string-width "^1.0.2 || 2 || 3 || 4"
-
-widest-line@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
- integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
- dependencies:
- string-width "^4.0.0"
-
-word-wrap@^1.2.3:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
- integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
-
-wrap-ansi@^6.2.0:
- version "6.2.0"
- resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
- integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
-wrappy@1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
- integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
-
-write-file-atomic@^3.0.0:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
- integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
- dependencies:
- imurmurhash "^0.1.4"
- is-typedarray "^1.0.0"
- signal-exit "^3.0.2"
- typedarray-to-buffer "^3.1.5"
-
-xdg-basedir@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
- integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
-
-xtend@^4.0.0:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
- integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
-
-y18n@^4.0.0:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4"
- integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==
-
-yallist@^3.0.0, yallist@^3.1.1:
- version "3.1.1"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
- integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
-
-yallist@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
- integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-
-yargs-parser@^18.1.2:
- version "18.1.3"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
- integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
- dependencies:
- camelcase "^5.0.0"
- decamelize "^1.2.0"
-
-yargs@^15.4.1:
- version "15.4.1"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
- integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
- dependencies:
- cliui "^6.0.0"
- decamelize "^1.2.0"
- find-up "^4.1.0"
- get-caller-file "^2.0.1"
- require-directory "^2.1.1"
- require-main-filename "^2.0.0"
- set-blocking "^2.0.0"
- string-width "^4.2.0"
- which-module "^2.0.0"
- y18n "^4.0.0"
- yargs-parser "^18.1.2"
-
-yocto-queue@^0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
- integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
-
-zip-stream@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79"
- integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==
- dependencies:
- archiver-utils "^2.1.0"
- compress-commons "^4.1.0"
- readable-stream "^3.6.0"
diff --git a/compose.yaml b/compose.yaml
new file mode 100644
index 00000000..f81cdf21
--- /dev/null
+++ b/compose.yaml
@@ -0,0 +1,32 @@
+services:
+ app:
+ build:
+ context: .
+ dockerfile: docker/web/Dockerfile
+ ports:
+ - "3000:3000"
+ environment:
+ NODE_ENV: production
+ DATABASE_PATH: /data/app/app.db
+ SESSION_SECRET: ${SESSION_SECRET:-change-me}
+ CADDY_API_URL: http://caddy:2019
+ CERTS_DIRECTORY: /data/certs
+ volumes:
+ - ./data/app:/data/app
+ - ./data/certs:/data/certs
+ depends_on:
+ - caddy
+
+ caddy:
+ build:
+ context: .
+ dockerfile: docker/caddy/Dockerfile
+ ports:
+ - "80:80"
+ - "443:443"
+ - "2019:2019"
+ environment:
+ PRIMARY_DOMAIN: ${PRIMARY_DOMAIN:-caddyproxymanager.com}
+ volumes:
+ - ./data/caddy:/data
+ - ./data/certs:/data/certs:ro
diff --git a/docker/.dive-ci b/docker/.dive-ci
deleted file mode 100644
index 7a408bdf..00000000
--- a/docker/.dive-ci
+++ /dev/null
@@ -1,14 +0,0 @@
-rules:
- # If the efficiency is measured below X%, mark as failed.
- # Expressed as a ratio between 0-1.
- lowestEfficiency: 0.99
-
- # If the amount of wasted space is at least X or larger than X, mark as failed.
- # Expressed in B, KB, MB, and GB.
- highestWastedBytes: 15MB
-
- # If the amount of wasted space makes up for X% or more of the image, mark as failed.
- # Note: the base image layer is NOT included in the total image size.
- # Expressed as a ratio between 0-1; fails if the threshold is met or crossed.
- highestUserWastedPercent: 0.02
-
diff --git a/docker/Dockerfile b/docker/Dockerfile
deleted file mode 100644
index 0603e2de..00000000
--- a/docker/Dockerfile
+++ /dev/null
@@ -1,66 +0,0 @@
-# This is a Dockerfile intended to be built using `docker buildx`
-# for multi-arch support. Building with `docker build` may have unexpected results.
-
-# This file assumes that the frontend has been built using ./scripts/frontend-build
-
-FROM nginxproxymanager/testca AS testca
-FROM letsencrypt/pebble AS pebbleca
-FROM nginxproxymanager/nginx-full:certbot-node
-
-ARG TARGETPLATFORM
-ARG BUILD_VERSION
-ARG BUILD_COMMIT
-ARG BUILD_DATE
-
-# See: https://github.com/just-containers/s6-overlay/blob/master/README.md
-ENV SUPPRESS_NO_CONFIG_WARNING=1 \
- S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
- S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
- S6_FIX_ATTRS_HIDDEN=1 \
- S6_KILL_FINISH_MAXTIME=10000 \
- S6_VERBOSITY=1 \
- NODE_ENV=production \
- NPM_BUILD_VERSION="${BUILD_VERSION}" \
- NPM_BUILD_COMMIT="${BUILD_COMMIT}" \
- NPM_BUILD_DATE="${BUILD_DATE}" \
- NODE_OPTIONS="--openssl-legacy-provider"
-
-RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
- && apt-get update \
- && apt-get install -y --no-install-recommends jq logrotate \
- && apt-get clean \
- && rm -rf /var/lib/apt/lists/*
-
-# s6 overlay
-COPY docker/scripts/install-s6 /tmp/install-s6
-RUN /tmp/install-s6 "${TARGETPLATFORM}" && rm -f /tmp/install-s6
-
-EXPOSE 80 81 443
-
-COPY backend /app
-COPY frontend/dist /app/frontend
-COPY global /app/global
-
-WORKDIR /app
-RUN yarn install \
- && yarn cache clean
-
-# add late to limit cache-busting by modifications
-COPY docker/rootfs /
-COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
-COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt
-
-# Remove frontend service not required for prod, dev nginx config as well
-RUN rm -rf /etc/s6-overlay/s6-rc.d/user/contents.d/frontend /etc/nginx/conf.d/dev.conf \
- && chmod 644 /etc/logrotate.d/nginx-proxy-manager
-
-VOLUME [ "/data" ]
-ENTRYPOINT [ "/init" ]
-
-LABEL org.label-schema.schema-version="1.0" \
- org.label-schema.license="MIT" \
- org.label-schema.name="nginx-proxy-manager" \
- org.label-schema.description="Docker container for managing Nginx proxy hosts with a simple, powerful interface " \
- org.label-schema.url="https://github.com/jc21/nginx-proxy-manager" \
- org.label-schema.vcs-url="https://github.com/jc21/nginx-proxy-manager.git" \
- org.label-schema.cmd="docker run --rm -ti jc21/nginx-proxy-manager:latest"
diff --git a/docker/caddy/Caddyfile b/docker/caddy/Caddyfile
new file mode 100644
index 00000000..b8e887ac
--- /dev/null
+++ b/docker/caddy/Caddyfile
@@ -0,0 +1,8 @@
+{
+ admin 0.0.0.0:2019
+}
+
+{$PRIMARY_DOMAIN:caddyproxymanager.com} {
+ header Strict-Transport-Security "max-age=63072000"
+ respond "Caddy Proxy Manager is running" 200
+}
diff --git a/docker/caddy/Dockerfile b/docker/caddy/Dockerfile
new file mode 100644
index 00000000..5943d237
--- /dev/null
+++ b/docker/caddy/Dockerfile
@@ -0,0 +1,12 @@
+# syntax=docker/dockerfile:1.6
+
+FROM caddy:2-builder AS builder
+RUN xcaddy build \
+ --with github.com/caddy-dns/cloudflare \
+ --with github.com/mholt/caddy-l4
+
+FROM caddy:2
+COPY --from=builder /usr/bin/caddy /usr/bin/caddy
+COPY docker/caddy/Caddyfile /etc/caddy/Caddyfile
+
+EXPOSE 80 443 2019
diff --git a/docker/ci.env b/docker/ci.env
deleted file mode 100644
index 7128295d..00000000
--- a/docker/ci.env
+++ /dev/null
@@ -1,8 +0,0 @@
-AUTHENTIK_SECRET_KEY=gl8woZe8L6IIX8SC0c5Ocsj0xPkX5uJo5DVZCFl+L/QGbzuplfutYuua2ODNLEiDD3aFd9H2ylJmrke0
-AUTHENTIK_REDIS__HOST=authentik-redis
-AUTHENTIK_POSTGRESQL__HOST=db-postgres
-AUTHENTIK_POSTGRESQL__USER=authentik
-AUTHENTIK_POSTGRESQL__NAME=authentik
-AUTHENTIK_POSTGRESQL__PASSWORD=07EKS5NLI6Tpv68tbdvrxfvj
-AUTHENTIK_BOOTSTRAP_PASSWORD=admin
-AUTHENTIK_BOOTSTRAP_EMAIL=admin@example.com
diff --git a/docker/ci/postgres/authentik.sql.gz b/docker/ci/postgres/authentik.sql.gz
deleted file mode 100644
index 49665d4e..00000000
Binary files a/docker/ci/postgres/authentik.sql.gz and /dev/null differ
diff --git a/docker/dev/Dockerfile b/docker/dev/Dockerfile
deleted file mode 100644
index dcb1f1f9..00000000
--- a/docker/dev/Dockerfile
+++ /dev/null
@@ -1,40 +0,0 @@
-FROM nginxproxymanager/testca AS testca
-FROM letsencrypt/pebble AS pebbleca
-FROM nginxproxymanager/nginx-full:certbot-node
-LABEL maintainer="Jamie Curnow "
-
-SHELL ["/bin/bash", "-o", "pipefail", "-c"]
-
-ENV SUPPRESS_NO_CONFIG_WARNING=1 \
- S6_BEHAVIOUR_IF_STAGE2_FAILS=1 \
- S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
- S6_FIX_ATTRS_HIDDEN=1 \
- S6_KILL_FINISH_MAXTIME=10000 \
- S6_VERBOSITY=2 \
- NODE_OPTIONS="--openssl-legacy-provider"
-
-RUN echo "fs.file-max = 65535" > /etc/sysctl.conf \
- && apt-get update \
- && apt-get install -y jq python3-pip logrotate \
- && apt-get clean \
- && rm -rf /var/lib/apt/lists/*
-
-# Task
-WORKDIR /usr
-RUN curl -sL https://taskfile.dev/install.sh | sh
-WORKDIR /root
-
-COPY rootfs /
-COPY scripts/install-s6 /tmp/install-s6
-RUN rm -f /etc/nginx/conf.d/production.conf \
- && chmod 644 /etc/logrotate.d/nginx-proxy-manager \
- && /tmp/install-s6 "${TARGETPLATFORM}" \
- && rm -f /tmp/install-s6 \
- && chmod 644 -R /root/.cache
-
-# Certs for testing purposes
-COPY --from=pebbleca /test/certs/pebble.minica.pem /etc/ssl/certs/pebble.minica.pem
-COPY --from=testca /home/step/certs/root_ca.crt /etc/ssl/certs/NginxProxyManager.crt
-
-EXPOSE 80 81 443
-ENTRYPOINT [ "/init" ]
diff --git a/docker/dev/dnsrouter-config.json b/docker/dev/dnsrouter-config.json
deleted file mode 100644
index a4e538d7..00000000
--- a/docker/dev/dnsrouter-config.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "log": {
- "format": "nice",
- "level": "debug"
- },
- "servers": [
- {
- "host": "0.0.0.0",
- "port": 53,
- "upstreams": [
- {
- "regex": "website[0-9]+.example\\.com",
- "upstream": "127.0.0.11"
- },
- {
- "regex": ".*\\.example\\.com",
- "upstream": "1.1.1.1"
- },
- {
- "regex": "local",
- "nxdomain": true
- }
- ],
- "internal": null,
- "default_upstream": "127.0.0.11"
- }
- ]
-}
diff --git a/docker/dev/letsencrypt.ini b/docker/dev/letsencrypt.ini
deleted file mode 100644
index 93647b64..00000000
--- a/docker/dev/letsencrypt.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-text = True
-non-interactive = True
-webroot-path = /data/letsencrypt-acme-challenge
-key-type = ecdsa
-elliptic-curve = secp384r1
-preferred-chain = ISRG Root X1
-server =
diff --git a/docker/dev/pdns-db.sql b/docker/dev/pdns-db.sql
deleted file mode 100644
index c182cf78..00000000
--- a/docker/dev/pdns-db.sql
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
-
-How this was generated:
-1. bring up an empty pdns stack
-2. use api to create a zone ...
-
-curl -X POST \
- 'http://npm.dev:8081/api/v1/servers/localhost/zones' \
- --header 'X-API-Key: npm' \
- --header 'Content-Type: application/json' \
- --data-raw '{
- "name": "example.com.",
- "kind": "Native",
- "masters": [],
- "nameservers": [
- "ns1.pdns.",
- "ns2.pdns."
- ]
-}'
-
-3. Dump sql:
-
-docker exec -ti npm.pdns.db mysqldump -u pdns -p pdns
-
-*/
-
-----------------------------------------------------------------------
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8mb4 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-
---
--- Table structure for table `comments`
---
-
-DROP TABLE IF EXISTS `comments`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `comments` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `domain_id` int(11) NOT NULL,
- `name` varchar(255) NOT NULL,
- `type` varchar(10) NOT NULL,
- `modified_at` int(11) NOT NULL,
- `account` varchar(40) CHARACTER SET utf8mb3 DEFAULT NULL,
- `comment` text CHARACTER SET utf8mb3 NOT NULL,
- PRIMARY KEY (`id`),
- KEY `comments_name_type_idx` (`name`,`type`),
- KEY `comments_order_idx` (`domain_id`,`modified_at`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `comments`
---
-
-LOCK TABLES `comments` WRITE;
-/*!40000 ALTER TABLE `comments` DISABLE KEYS */;
-/*!40000 ALTER TABLE `comments` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `cryptokeys`
---
-
-DROP TABLE IF EXISTS `cryptokeys`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `cryptokeys` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `domain_id` int(11) NOT NULL,
- `flags` int(11) NOT NULL,
- `active` tinyint(1) DEFAULT NULL,
- `published` tinyint(1) DEFAULT 1,
- `content` text DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `domainidindex` (`domain_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `cryptokeys`
---
-
-LOCK TABLES `cryptokeys` WRITE;
-/*!40000 ALTER TABLE `cryptokeys` DISABLE KEYS */;
-/*!40000 ALTER TABLE `cryptokeys` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `domainmetadata`
---
-
-DROP TABLE IF EXISTS `domainmetadata`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `domainmetadata` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `domain_id` int(11) NOT NULL,
- `kind` varchar(32) DEFAULT NULL,
- `content` text DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `domainmetadata_idx` (`domain_id`,`kind`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `domainmetadata`
---
-
-LOCK TABLES `domainmetadata` WRITE;
-/*!40000 ALTER TABLE `domainmetadata` DISABLE KEYS */;
-INSERT INTO `domainmetadata` VALUES
-(1,1,'SOA-EDIT-API','DEFAULT');
-/*!40000 ALTER TABLE `domainmetadata` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `domains`
---
-
-DROP TABLE IF EXISTS `domains`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `domains` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(255) NOT NULL,
- `master` varchar(128) DEFAULT NULL,
- `last_check` int(11) DEFAULT NULL,
- `type` varchar(8) NOT NULL,
- `notified_serial` int(10) unsigned DEFAULT NULL,
- `account` varchar(40) CHARACTER SET utf8mb3 DEFAULT NULL,
- `options` varchar(64000) DEFAULT NULL,
- `catalog` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `name_index` (`name`),
- KEY `catalog_idx` (`catalog`)
-) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `domains`
---
-
-LOCK TABLES `domains` WRITE;
-/*!40000 ALTER TABLE `domains` DISABLE KEYS */;
-INSERT INTO `domains` VALUES
-(1,'example.com','',NULL,'NATIVE',NULL,'',NULL,NULL);
-/*!40000 ALTER TABLE `domains` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `records`
---
-
-DROP TABLE IF EXISTS `records`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `records` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT,
- `domain_id` int(11) DEFAULT NULL,
- `name` varchar(255) DEFAULT NULL,
- `type` varchar(10) DEFAULT NULL,
- `content` varchar(64000) DEFAULT NULL,
- `ttl` int(11) DEFAULT NULL,
- `prio` int(11) DEFAULT NULL,
- `disabled` tinyint(1) DEFAULT 0,
- `ordername` varchar(255) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
- `auth` tinyint(1) DEFAULT 1,
- PRIMARY KEY (`id`),
- KEY `nametype_index` (`name`,`type`),
- KEY `domain_id` (`domain_id`),
- KEY `ordername` (`ordername`)
-) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `records`
---
-
-LOCK TABLES `records` WRITE;
-/*!40000 ALTER TABLE `records` DISABLE KEYS */;
-INSERT INTO `records` VALUES
-(1,1,'example.com','NS','ns1.pdns',1500,0,0,NULL,1),
-(2,1,'example.com','NS','ns2.pdns',1500,0,0,NULL,1),
-(3,1,'example.com','SOA','a.misconfigured.dns.server.invalid hostmaster.example.com 2023030501 10800 3600 604800 3600',1500,0,0,NULL,1);
-/*!40000 ALTER TABLE `records` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `supermasters`
---
-
-DROP TABLE IF EXISTS `supermasters`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `supermasters` (
- `ip` varchar(64) NOT NULL,
- `nameserver` varchar(255) NOT NULL,
- `account` varchar(40) CHARACTER SET utf8mb3 NOT NULL,
- PRIMARY KEY (`ip`,`nameserver`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `supermasters`
---
-
-LOCK TABLES `supermasters` WRITE;
-/*!40000 ALTER TABLE `supermasters` DISABLE KEYS */;
-/*!40000 ALTER TABLE `supermasters` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `tsigkeys`
---
-
-DROP TABLE IF EXISTS `tsigkeys`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `tsigkeys` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(255) DEFAULT NULL,
- `algorithm` varchar(50) DEFAULT NULL,
- `secret` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`id`),
- UNIQUE KEY `namealgoindex` (`name`,`algorithm`)
-) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `tsigkeys`
---
-
-LOCK TABLES `tsigkeys` WRITE;
-/*!40000 ALTER TABLE `tsigkeys` DISABLE KEYS */;
-/*!40000 ALTER TABLE `tsigkeys` ENABLE KEYS */;
-UNLOCK TABLES;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
diff --git a/docker/dev/pebble-config.json b/docker/dev/pebble-config.json
deleted file mode 100644
index ea937905..00000000
--- a/docker/dev/pebble-config.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "pebble": {
- "listenAddress": "0.0.0.0:443",
- "managementListenAddress": "0.0.0.0:15000",
- "certificate": "test/certs/localhost/cert.pem",
- "privateKey": "test/certs/localhost/key.pem",
- "httpPort": 80,
- "tlsPort": 443,
- "ocspResponderURL": "",
- "externalAccountBindingRequired": false
- }
-}
diff --git a/docker/dev/squid.conf b/docker/dev/squid.conf
deleted file mode 100644
index cdd749f5..00000000
--- a/docker/dev/squid.conf
+++ /dev/null
@@ -1,92 +0,0 @@
-# WELCOME TO SQUID 6.6
-# ----------------------------
-#
-# This is the documentation for the Squid configuration file.
-# This documentation can also be found online at:
-# http://www.squid-cache.org/Doc/config/
-#
-# You may wish to look at the Squid home page and wiki for the
-# FAQ and other documentation:
-# http://www.squid-cache.org/
-# https://wiki.squid-cache.org/SquidFaq
-# https://wiki.squid-cache.org/ConfigExamples
-#
-
-# Example rule allowing access from your local networks.
-# Adapt to list your (internal) IP networks from where browsing
-# should be allowed
-acl localnet src 0.0.0.1-0.255.255.255 # RFC 1122 "this" network (LAN)
-acl localnet src 10.0.0.0/8 # RFC 1918 local private network (LAN)
-acl localnet src 100.64.0.0/10 # RFC 6598 shared address space (CGN)
-acl localnet src 169.254.0.0/16 # RFC 3927 link-local (directly plugged) machines
-acl localnet src 172.0.0.0/8
-acl localnet src 192.168.0.0/16 # RFC 1918 local private network (LAN)
-acl localnet src fc00::/7 # RFC 4193 local private network range
-acl localnet src fe80::/10 # RFC 4291 link-local (directly plugged) machines
-
-acl SSL_ports port 443
-acl Safe_ports port 80 # http
-acl Safe_ports port 81
-acl Safe_ports port 443 # https
-
-#
-# Recommended minimum Access Permission configuration:
-#
-# Deny requests to certain unsafe ports
-http_access deny !Safe_ports
-
-# Deny CONNECT to other than secure SSL ports
-http_access deny CONNECT !SSL_ports
-
-# Only allow cachemgr access from localhost
-http_access allow localhost manager
-http_access deny manager
-
-# This default configuration only allows localhost requests because a more
-# permissive Squid installation could introduce new attack vectors into the
-# network by proxying external TCP connections to unprotected services.
-http_access allow localhost
-
-# The two deny rules below are unnecessary in this default configuration
-# because they are followed by a "deny all" rule. However, they may become
-# critically important when you start allowing external requests below them.
-
-# Protect web applications running on the same server as Squid. They often
-# assume that only local users can access them at "localhost" ports.
-http_access deny to_localhost
-
-# Protect cloud servers that provide local users with sensitive info about
-# their server via certain well-known link-local (a.k.a. APIPA) addresses.
-http_access deny to_linklocal
-
-#
-# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
-#
-include /etc/squid/conf.d/*.conf
-
-# For example, to allow access from your local networks, you may uncomment the
-# following rule (and/or add rules that match your definition of "local"):
-# http_access allow localnet
-
-# And finally deny all other access to this proxy
-http_access deny all
-
-# Squid normally listens to port 3128
-http_port 3128
-
-# Leave coredumps in the first cache dir
-coredump_dir /var/spool/squid
-
-#
-# Add any of your own refresh_pattern entries above these.
-#
-refresh_pattern ^ftp: 1440 20% 10080
-refresh_pattern -i (/cgi-bin/|\?) 0 0% 0
-refresh_pattern \/(Packages|Sources)(|\.bz2|\.gz|\.xz)$ 0 0% 0 refresh-ims
-refresh_pattern \/Release(|\.gpg)$ 0 0% 0 refresh-ims
-refresh_pattern \/InRelease$ 0 0% 0 refresh-ims
-refresh_pattern \/(Translation-.*)(|\.bz2|\.gz|\.xz)$ 0 0% 0 refresh-ims
-# example pattern for deb packages
-#refresh_pattern (\.deb|\.udeb)$ 129600 100% 129600
-refresh_pattern . 0 20% 4320
-
diff --git a/docker/docker-compose.ci.mysql.yml b/docker/docker-compose.ci.mysql.yml
deleted file mode 100644
index 108a1dca..00000000
--- a/docker/docker-compose.ci.mysql.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
-services:
-
- fullstack:
- environment:
- DB_MYSQL_HOST: 'db-mysql'
- DB_MYSQL_PORT: '3306'
- DB_MYSQL_USER: 'npm'
- DB_MYSQL_PASSWORD: 'npmpass'
- DB_MYSQL_NAME: 'npm'
- depends_on:
- - db-mysql
-
- db-mysql:
- image: jc21/mariadb-aria
- environment:
- MYSQL_ROOT_PASSWORD: 'npm'
- MYSQL_DATABASE: 'npm'
- MYSQL_USER: 'npm'
- MYSQL_PASSWORD: 'npmpass'
- MARIADB_AUTO_UPGRADE: '1'
- volumes:
- - mysql_vol:/var/lib/mysql
- networks:
- - fulltest
-
-volumes:
- mysql_vol:
diff --git a/docker/docker-compose.ci.postgres.yml b/docker/docker-compose.ci.postgres.yml
deleted file mode 100644
index c4468c68..00000000
--- a/docker/docker-compose.ci.postgres.yml
+++ /dev/null
@@ -1,78 +0,0 @@
-# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
-services:
-
- cypress:
- environment:
- CYPRESS_stack: 'postgres'
-
- fullstack:
- environment:
- DB_POSTGRES_HOST: 'db-postgres'
- DB_POSTGRES_PORT: '5432'
- DB_POSTGRES_USER: 'npm'
- DB_POSTGRES_PASSWORD: 'npmpass'
- DB_POSTGRES_NAME: 'npm'
- depends_on:
- - db-postgres
- - authentik
- - authentik-worker
- - authentik-ldap
-
- db-postgres:
- image: postgres:latest
- environment:
- POSTGRES_USER: 'npm'
- POSTGRES_PASSWORD: 'npmpass'
- POSTGRES_DB: 'npm'
- volumes:
- - psql_vol:/var/lib/postgresql/data
- - ./ci/postgres:/docker-entrypoint-initdb.d
- networks:
- - fulltest
-
- authentik-redis:
- image: 'redis:alpine'
- command: --save 60 1 --loglevel warning
- restart: unless-stopped
- healthcheck:
- test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
- start_period: 20s
- interval: 30s
- retries: 5
- timeout: 3s
- volumes:
- - redis_vol:/data
-
- authentik:
- image: ghcr.io/goauthentik/server:2024.10.1
- restart: unless-stopped
- command: server
- env_file:
- - ci.env
- depends_on:
- - authentik-redis
- - db-postgres
-
- authentik-worker:
- image: ghcr.io/goauthentik/server:2024.10.1
- restart: unless-stopped
- command: worker
- env_file:
- - ci.env
- depends_on:
- - authentik-redis
- - db-postgres
-
- authentik-ldap:
- image: ghcr.io/goauthentik/ldap:2024.10.1
- environment:
- AUTHENTIK_HOST: 'http://authentik:9000'
- AUTHENTIK_INSECURE: 'true'
- AUTHENTIK_TOKEN: 'wKYZuRcI0ETtb8vWzMCr04oNbhrQUUICy89hSpDln1OEKLjiNEuQ51044Vkp'
- restart: unless-stopped
- depends_on:
- - authentik
-
-volumes:
- psql_vol:
- redis_vol:
diff --git a/docker/docker-compose.ci.sqlite.yml b/docker/docker-compose.ci.sqlite.yml
deleted file mode 100644
index 1c5be48e..00000000
--- a/docker/docker-compose.ci.sqlite.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-# WARNING: This is a CI docker-compose file used for building and testing of the entire app, it should not be used for production.
-services:
-
- fullstack:
- environment:
- DB_SQLITE_FILE: '/data/mydb.sqlite'
- PUID: 1000
- PGID: 1000
- DISABLE_IPV6: 'true'
diff --git a/docker/docker-compose.ci.yml b/docker/docker-compose.ci.yml
deleted file mode 100644
index 280a0546..00000000
--- a/docker/docker-compose.ci.yml
+++ /dev/null
@@ -1,128 +0,0 @@
-# WARNING: This is a CI docker-compose file used for building
-# and testing of the entire app, it should not be used for production.
-# This is a base compose file, it should be extended with a
-# docker-compose.ci.*.yml file
-services:
-
- fullstack:
- image: "${IMAGE}:${BRANCH_LOWER}-ci-${BUILD_NUMBER}"
- environment:
- DEBUG: 'true'
- FORCE_COLOR: 1
- # Required for DNS Certificate provisioning in CI
- LE_SERVER: 'https://ca.internal/acme/acme/directory'
- REQUESTS_CA_BUNDLE: '/etc/ssl/certs/NginxProxyManager.crt'
- volumes:
- - 'npm_data_ci:/data'
- - 'npm_le_ci:/etc/letsencrypt'
- - './dev/letsencrypt.ini:/etc/letsencrypt.ini:ro'
- - './dev/resolv.conf:/etc/resolv.conf:ro'
- - '/etc/localtime:/etc/localtime:ro'
- healthcheck:
- test: ["CMD", "/usr/bin/check-health"]
- interval: 10s
- timeout: 3s
- expose:
- - '80-81/tcp'
- - '443/tcp'
- - '1500-1503/tcp'
- networks:
- fulltest:
- aliases:
- - website1.example.com
- - website2.example.com
- - website3.example.com
-
- stepca:
- image: jc21/testca
- volumes:
- - './dev/resolv.conf:/etc/resolv.conf:ro'
- - '/etc/localtime:/etc/localtime:ro'
- networks:
- fulltest:
- aliases:
- - ca.internal
-
- pdns:
- image: pschiffe/pdns-mysql:4.8
- volumes:
- - '/etc/localtime:/etc/localtime:ro'
- environment:
- PDNS_master: 'yes'
- PDNS_api: 'yes'
- PDNS_api_key: 'npm'
- PDNS_webserver: 'yes'
- PDNS_webserver_address: '0.0.0.0'
- PDNS_webserver_password: 'npm'
- PDNS_webserver-allow-from: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
- PDNS_version_string: 'anonymous'
- PDNS_default_ttl: 1500
- PDNS_allow_axfr_ips: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
- PDNS_gmysql_host: pdns-db
- PDNS_gmysql_port: 3306
- PDNS_gmysql_user: pdns
- PDNS_gmysql_password: pdns
- PDNS_gmysql_dbname: pdns
- depends_on:
- - pdns-db
- networks:
- fulltest:
- aliases:
- - ns1.pdns
- - ns2.pdns
-
- pdns-db:
- image: mariadb
- environment:
- MYSQL_ROOT_PASSWORD: 'pdns'
- MYSQL_DATABASE: 'pdns'
- MYSQL_USER: 'pdns'
- MYSQL_PASSWORD: 'pdns'
- volumes:
- - 'pdns_mysql_vol:/var/lib/mysql'
- - '/etc/localtime:/etc/localtime:ro'
- - './dev/pdns-db.sql:/docker-entrypoint-initdb.d/01_init.sql:ro'
- networks:
- - fulltest
-
- dnsrouter:
- image: jc21/dnsrouter
- volumes:
- - ./dev/dnsrouter-config.json.tmp:/dnsrouter-config.json:ro
- networks:
- - fulltest
-
- cypress:
- image: "${IMAGE}-cypress:ci-${BUILD_NUMBER}"
- build:
- context: ../
- dockerfile: test/cypress/Dockerfile
- environment:
- HTTP_PROXY: 'squid:3128'
- HTTPS_PROXY: 'squid:3128'
- volumes:
- - 'cypress_logs:/test/results'
- - './dev/resolv.conf:/etc/resolv.conf:ro'
- - '/etc/localtime:/etc/localtime:ro'
- command: cypress run --browser chrome --config-file=cypress/config/ci.js
- networks:
- - fulltest
-
- squid:
- image: ubuntu/squid
- volumes:
- - './dev/squid.conf:/etc/squid/squid.conf:ro'
- - './dev/resolv.conf:/etc/resolv.conf:ro'
- - '/etc/localtime:/etc/localtime:ro'
- networks:
- - fulltest
-
-volumes:
- cypress_logs:
- npm_data_ci:
- npm_le_ci:
- pdns_mysql_vol:
-
-networks:
- fulltest:
- name: "npm-${BRANCH_LOWER}-ci-${BUILD_NUMBER}"
diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml
deleted file mode 100644
index 5abe057b..00000000
--- a/docker/docker-compose.dev.yml
+++ /dev/null
@@ -1,268 +0,0 @@
-# WARNING: This is a DEVELOPMENT docker-compose file, it should not be used for production.
-services:
-
- fullstack:
- image: npm2dev:core
- container_name: npm2dev.core
- build:
- context: ./
- dockerfile: ./dev/Dockerfile
- ports:
- - 3080:80
- - 3081:81
- - 3443:443
- networks:
- nginx_proxy_manager:
- aliases:
- - website1.example.com
- - website2.example.com
- - website3.example.com
- environment:
- PUID: 1000
- PGID: 1000
- FORCE_COLOR: 1
- # specifically for dev:
- DEBUG: 'true'
- DEVELOPMENT: 'true'
- LE_STAGING: 'true'
- # db:
- # DB_MYSQL_HOST: 'db'
- # DB_MYSQL_PORT: '3306'
- # DB_MYSQL_USER: 'npm'
- # DB_MYSQL_PASSWORD: 'npm'
- # DB_MYSQL_NAME: 'npm'
- # db-postgres:
- DB_POSTGRES_HOST: 'db-postgres'
- DB_POSTGRES_PORT: '5432'
- DB_POSTGRES_USER: 'npm'
- DB_POSTGRES_PASSWORD: 'npmpass'
- DB_POSTGRES_NAME: 'npm'
- # DB_SQLITE_FILE: "/data/database.sqlite"
- # DISABLE_IPV6: "true"
- # Required for DNS Certificate provisioning testing:
- LE_SERVER: 'https://ca.internal/acme/acme/directory'
- REQUESTS_CA_BUNDLE: '/etc/ssl/certs/NginxProxyManager.crt'
- volumes:
- - npm_data:/data
- - le_data:/etc/letsencrypt
- - './dev/resolv.conf:/etc/resolv.conf:ro'
- - ../backend:/app
- - ../frontend:/app/frontend
- - ../global:/app/global
- healthcheck:
- test: ["CMD", "/usr/bin/check-health"]
- interval: 10s
- timeout: 3s
- depends_on:
- - db
- - db-postgres
- - authentik
- - authentik-worker
- - authentik-ldap
- working_dir: /app
-
- db:
- image: jc21/mariadb-aria
- container_name: npm2dev.db
- ports:
- - 33306:3306
- networks:
- - nginx_proxy_manager
- environment:
- MYSQL_ROOT_PASSWORD: 'npm'
- MYSQL_DATABASE: 'npm'
- MYSQL_USER: 'npm'
- MYSQL_PASSWORD: 'npm'
- volumes:
- - db_data:/var/lib/mysql
-
- db-postgres:
- image: postgres:latest
- container_name: npm2dev.db-postgres
- networks:
- - nginx_proxy_manager
- environment:
- POSTGRES_USER: 'npm'
- POSTGRES_PASSWORD: 'npmpass'
- POSTGRES_DB: 'npm'
- volumes:
- - psql_data:/var/lib/postgresql/data
- - ./ci/postgres:/docker-entrypoint-initdb.d
-
- stepca:
- image: jc21/testca
- container_name: npm2dev.stepca
- volumes:
- - './dev/resolv.conf:/etc/resolv.conf:ro'
- - '/etc/localtime:/etc/localtime:ro'
- networks:
- nginx_proxy_manager:
- aliases:
- - ca.internal
-
- dnsrouter:
- image: jc21/dnsrouter
- container_name: npm2dev.dnsrouter
- volumes:
- - ./dev/dnsrouter-config.json.tmp:/dnsrouter-config.json:ro
- networks:
- - nginx_proxy_manager
-
- swagger:
- image: swaggerapi/swagger-ui:latest
- container_name: npm2dev.swagger
- ports:
- - 3082:80
- environment:
- URL: "http://npm:81/api/schema"
- PORT: '80'
- depends_on:
- - fullstack
-
- squid:
- image: ubuntu/squid
- container_name: npm2dev.squid
- volumes:
- - './dev/squid.conf:/etc/squid/squid.conf:ro'
- - './dev/resolv.conf:/etc/resolv.conf:ro'
- - '/etc/localtime:/etc/localtime:ro'
- networks:
- - nginx_proxy_manager
- ports:
- - 8128:3128
-
- pdns:
- image: pschiffe/pdns-mysql:4.8
- container_name: npm2dev.pdns
- volumes:
- - '/etc/localtime:/etc/localtime:ro'
- environment:
- PDNS_master: 'yes'
- PDNS_api: 'yes'
- PDNS_api_key: 'npm'
- PDNS_webserver: 'yes'
- PDNS_webserver_address: '0.0.0.0'
- PDNS_webserver_password: 'npm'
- PDNS_webserver-allow-from: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
- PDNS_version_string: 'anonymous'
- PDNS_default_ttl: 1500
- PDNS_allow_axfr_ips: '127.0.0.0/8,192.0.0.0/8,10.0.0.0/8,172.0.0.0/8'
- PDNS_gmysql_host: pdns-db
- PDNS_gmysql_port: 3306
- PDNS_gmysql_user: pdns
- PDNS_gmysql_password: pdns
- PDNS_gmysql_dbname: pdns
- depends_on:
- - pdns-db
- networks:
- nginx_proxy_manager:
- aliases:
- - ns1.pdns
- - ns2.pdns
-
- pdns-db:
- image: mariadb
- container_name: npm2dev.pdns-db
- environment:
- MYSQL_ROOT_PASSWORD: 'pdns'
- MYSQL_DATABASE: 'pdns'
- MYSQL_USER: 'pdns'
- MYSQL_PASSWORD: 'pdns'
- volumes:
- - 'pdns_mysql:/var/lib/mysql'
- - '/etc/localtime:/etc/localtime:ro'
- - './dev/pdns-db.sql:/docker-entrypoint-initdb.d/01_init.sql:ro'
- networks:
- - nginx_proxy_manager
-
- cypress:
- image: npm2dev:cypress
- container_name: npm2dev.cypress
- build:
- context: ../
- dockerfile: test/cypress/Dockerfile
- environment:
- HTTP_PROXY: 'squid:3128'
- HTTPS_PROXY: 'squid:3128'
- volumes:
- - '../test/results:/results'
- - './dev/resolv.conf:/etc/resolv.conf:ro'
- - '/etc/localtime:/etc/localtime:ro'
- command: cypress run --browser chrome --config-file=cypress/config/ci.js
- networks:
- - nginx_proxy_manager
-
- authentik-redis:
- image: 'redis:alpine'
- container_name: npm2dev.authentik-redis
- command: --save 60 1 --loglevel warning
- networks:
- - nginx_proxy_manager
- restart: unless-stopped
- healthcheck:
- test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
- start_period: 20s
- interval: 30s
- retries: 5
- timeout: 3s
- volumes:
- - redis_data:/data
-
- authentik:
- image: ghcr.io/goauthentik/server:2024.10.1
- container_name: npm2dev.authentik
- restart: unless-stopped
- command: server
- networks:
- - nginx_proxy_manager
- env_file:
- - ci.env
- ports:
- - 9000:9000
- depends_on:
- - authentik-redis
- - db-postgres
-
- authentik-worker:
- image: ghcr.io/goauthentik/server:2024.10.1
- container_name: npm2dev.authentik-worker
- restart: unless-stopped
- command: worker
- networks:
- - nginx_proxy_manager
- env_file:
- - ci.env
- depends_on:
- - authentik-redis
- - db-postgres
-
- authentik-ldap:
- image: ghcr.io/goauthentik/ldap:2024.10.1
- container_name: npm2dev.authentik-ldap
- networks:
- - nginx_proxy_manager
- environment:
- AUTHENTIK_HOST: 'http://authentik:9000'
- AUTHENTIK_INSECURE: 'true'
- AUTHENTIK_TOKEN: 'wKYZuRcI0ETtb8vWzMCr04oNbhrQUUICy89hSpDln1OEKLjiNEuQ51044Vkp'
- restart: unless-stopped
- depends_on:
- - authentik
-
-volumes:
- npm_data:
- name: npm2dev_core_data
- le_data:
- name: npm2dev_le_data
- db_data:
- name: npm2dev_db_data
- pdns_mysql:
- name: npnpm2dev_pdns_mysql
- psql_data:
- name: npm2dev_psql_data
- redis_data:
- name: npm2dev_redis_data
-
-networks:
- nginx_proxy_manager:
- name: npm2dev_network
diff --git a/docker/rootfs/etc/letsencrypt.ini b/docker/rootfs/etc/letsencrypt.ini
deleted file mode 100644
index aae53b90..00000000
--- a/docker/rootfs/etc/letsencrypt.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-text = True
-non-interactive = True
-webroot-path = /data/letsencrypt-acme-challenge
-key-type = ecdsa
-elliptic-curve = secp384r1
-preferred-chain = ISRG Root X1
diff --git a/docker/rootfs/etc/logrotate.d/nginx-proxy-manager b/docker/rootfs/etc/logrotate.d/nginx-proxy-manager
deleted file mode 100644
index de977297..00000000
--- a/docker/rootfs/etc/logrotate.d/nginx-proxy-manager
+++ /dev/null
@@ -1,27 +0,0 @@
-/data/logs/*_access.log /data/logs/*/access.log {
- su npm npm
- create 0644
- weekly
- rotate 4
- missingok
- notifempty
- compress
- sharedscripts
- postrotate
- kill -USR1 `cat /run/nginx/nginx.pid 2>/dev/null` 2>/dev/null || true
- endscript
-}
-
-/data/logs/*_error.log /data/logs/*/error.log {
- su npm npm
- create 0644
- weekly
- rotate 10
- missingok
- notifempty
- compress
- sharedscripts
- postrotate
- kill -USR1 `cat /run/nginx/nginx.pid 2>/dev/null` 2>/dev/null || true
- endscript
-}
diff --git a/docker/rootfs/etc/nginx/conf.d/default.conf b/docker/rootfs/etc/nginx/conf.d/default.conf
deleted file mode 100644
index e4262e1d..00000000
--- a/docker/rootfs/etc/nginx/conf.d/default.conf
+++ /dev/null
@@ -1,39 +0,0 @@
-# "You are not configured" page, which is the default if another default doesn't exist
-server {
- listen 80;
- listen [::]:80;
-
- set $forward_scheme "http";
- set $server "127.0.0.1";
- set $port "80";
-
- server_name localhost-nginx-proxy-manager;
- access_log /data/logs/fallback_access.log standard;
- error_log /data/logs/fallback_error.log warn;
- include conf.d/include/assets.conf;
- include conf.d/include/block-exploits.conf;
- include conf.d/include/letsencrypt-acme-challenge.conf;
-
- location / {
- index index.html;
- root /var/www/html;
- }
-}
-
-# First 443 Host, which is the default if another default doesn't exist
-server {
- listen 443 ssl;
- listen [::]:443 ssl;
-
- set $forward_scheme "https";
- set $server "127.0.0.1";
- set $port "443";
-
- server_name localhost;
- access_log /data/logs/fallback_access.log standard;
- error_log /dev/null crit;
- include conf.d/include/ssl-ciphers.conf;
- ssl_reject_handshake on;
-
- return 444;
-}
diff --git a/docker/rootfs/etc/nginx/conf.d/dev.conf b/docker/rootfs/etc/nginx/conf.d/dev.conf
deleted file mode 100644
index edbdec8a..00000000
--- a/docker/rootfs/etc/nginx/conf.d/dev.conf
+++ /dev/null
@@ -1,29 +0,0 @@
-server {
- listen 81 default;
- listen [::]:81 default;
-
- server_name nginxproxymanager-dev;
- root /app/frontend/dist;
- access_log /dev/null;
-
- location /api {
- return 302 /api/;
- }
-
- location /api/ {
- add_header X-Served-By $host;
- proxy_set_header Host $host;
- proxy_set_header X-Forwarded-Scheme $scheme;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Forwarded-For $remote_addr;
- proxy_pass http://127.0.0.1:3000/;
-
- proxy_read_timeout 15m;
- proxy_send_timeout 15m;
- }
-
- location / {
- index index.html;
- try_files $uri $uri.html $uri/ /index.html;
- }
-}
diff --git a/docker/rootfs/etc/nginx/conf.d/include/.gitignore b/docker/rootfs/etc/nginx/conf.d/include/.gitignore
deleted file mode 100644
index 5291fe15..00000000
--- a/docker/rootfs/etc/nginx/conf.d/include/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-resolvers.conf
diff --git a/docker/rootfs/etc/nginx/conf.d/include/assets.conf b/docker/rootfs/etc/nginx/conf.d/include/assets.conf
deleted file mode 100644
index 5a90beb8..00000000
--- a/docker/rootfs/etc/nginx/conf.d/include/assets.conf
+++ /dev/null
@@ -1,31 +0,0 @@
-location ~* ^.*\.(css|js|jpe?g|gif|png|webp|woff|woff2|eot|ttf|svg|ico|css\.map|js\.map)$ {
- if_modified_since off;
-
- # use the public cache
- proxy_cache public-cache;
- proxy_cache_key $host$request_uri;
-
- # ignore these headers for media
- proxy_ignore_headers Set-Cookie Cache-Control Expires X-Accel-Expires;
-
- # cache 200s and also 404s (not ideal but there are a few 404 images for some reason)
- proxy_cache_valid any 30m;
- proxy_cache_valid 404 1m;
-
- # strip this header to avoid If-Modified-Since requests
- proxy_hide_header Last-Modified;
- proxy_hide_header Cache-Control;
- proxy_hide_header Vary;
-
- proxy_cache_bypass 0;
- proxy_no_cache 0;
-
- proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504 http_404;
- proxy_connect_timeout 5s;
- proxy_read_timeout 45s;
-
- expires @30m;
- access_log off;
-
- include conf.d/include/proxy.conf;
-}
diff --git a/docker/rootfs/etc/nginx/conf.d/include/block-exploits.conf b/docker/rootfs/etc/nginx/conf.d/include/block-exploits.conf
deleted file mode 100644
index 76bc9e79..00000000
--- a/docker/rootfs/etc/nginx/conf.d/include/block-exploits.conf
+++ /dev/null
@@ -1,347 +0,0 @@
-## Block SQL injections
-set $block_sql_injections 0;
-
-# Traditional SQL injection patterns
-if ($query_string ~ "union.*select.*\(") {
- set $block_sql_injections 1;
-}
-
-if ($query_string ~ "union.*all.*select.*") {
- set $block_sql_injections 1;
-}
-
-if ($query_string ~ "concat.*\(") {
- set $block_sql_injections 1;
-}
-
-# Enhanced SQL injection patterns
-if ($query_string ~ "(select|insert|update|delete|drop|create|alter|exec|execute).*[\s\(]") {
- set $block_sql_injections 1;
-}
-
-if ($query_string ~ "(or|and).*[\s]*[0-9]+[\s]*[=<>]+[\s]*[0-9]+") {
- set $block_sql_injections 1;
-}
-
-if ($query_string ~ "[\s]*['\"`][\s]*(or|and)[\s]*['\"`][\s]*[=<>]") {
- set $block_sql_injections 1;
-}
-
-if ($query_string ~ "information_schema|mysql\.user|pg_user|pg_shadow") {
- set $block_sql_injections 1;
-}
-
-if ($query_string ~ "(sleep|benchmark|waitfor)\s*\(") {
- set $block_sql_injections 1;
-}
-
-# NoSQL injection patterns (MongoDB, CouchDB, etc.)
-if ($query_string ~ "(\$ne|\$gt|\$gte|\$lt|\$lte|\$regex|\$where)") {
- set $block_sql_injections 1;
-}
-
-if ($query_string ~ "javascript:|constructor|prototype|__proto__") {
- set $block_sql_injections 1;
-}
-
-if ($block_sql_injections = 1) {
- return 403;
-}
-
-## Block file injections
-set $block_file_injections 0;
-
-# Remote file inclusion
-if ($query_string ~ "[a-zA-Z0-9_]=(https?|ftp|ftps|file|data|php|expect|gopher)://") {
- set $block_file_injections 1;
-}
-
-# Directory traversal - enhanced patterns
-if ($query_string ~ "[a-zA-Z0-9_]=(\.\.//?)+") {
- set $block_file_injections 1;
-}
-
-if ($query_string ~ "[a-zA-Z0-9_]=/([a-z0-9_.]//?)+") {
- set $block_file_injections 1;
-}
-
-# Additional traversal patterns
-if ($query_string ~ "(\.\./)|(\.\.\\\\)|(\.\.%2f)|(\.\.%5c)") {
- set $block_file_injections 1;
-}
-
-if ($query_string ~ "(\.\.%252f)|(\.\.%255c)|(%2e%2e%2f)|(%2e%2e%5c)") {
- set $block_file_injections 1;
-}
-
-# Windows system files
-if ($query_string ~ "(boot\.ini)|(win\.ini)|(system\.ini)|(\.\.\\\\windows)") {
- set $block_file_injections 1;
-}
-
-# Unix system files
-if ($query_string ~ "(\/etc\/passwd)|(\/etc\/shadow)|(\/etc\/hosts)") {
- set $block_file_injections 1;
-}
-
-# Null bytes and dangerous encoding attacks
-if ($query_string ~ "(%00|%0a%0d|%0d%0a)") {
- set $block_file_injections 1;
-}
-
-if ($block_file_injections = 1) {
- return 403;
-}
-
-## Block common exploits
-set $block_common_exploits 0;
-
-# XSS protection - enhanced patterns
-if ($query_string ~ "(<|%3C).*(script|iframe|object|embed|applet|meta|link|form|input|img).*(\s|%20).*(>|%3E)") {
- set $block_common_exploits 1;
-}
-
-if ($query_string ~ "(javascript|vbscript|onload|onerror|onclick|onmouseover|onfocus|onblur|onchange|onsubmit):") {
- set $block_common_exploits 1;
-}
-
-if ($query_string ~ "(<|%3C).*script.*(>|%3E)") {
- set $block_common_exploits 1;
-}
-
-# Enhanced XSS vectors
-if ($query_string ~ "(document\.|window\.|eval\(|setTimeout\(|setInterval\(|function\s*\()") {
- set $block_common_exploits 1;
-}
-
-if ($query_string ~ "(expression\s*\(|url\s*\(|@import|behaviour:)") {
- set $block_common_exploits 1;
-}
-
-# PHP globals and superglobals
-if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") {
- set $block_common_exploits 1;
-}
-
-if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") {
- set $block_common_exploits 1;
-}
-
-if ($query_string ~ "(_GET|_POST|_COOKIE|_SESSION|_FILES|_SERVER|_ENV)(=|\[|\%[0-9A-Z]{0,2})") {
- set $block_common_exploits 1;
-}
-
-# System information disclosure
-if ($query_string ~ "proc/self/environ") {
- set $block_common_exploits 1;
-}
-
-if ($query_string ~ "mosConfig_[a-zA-Z_]{1,21}(=|\%3D)") {
- set $block_common_exploits 1;
-}
-
-# Encoding attacks
-if ($query_string ~ "base64_(en|de)code\(.*\)") {
- set $block_common_exploits 1;
-}
-
-# Command injection patterns
-if ($query_string ~ "(`|%60|\$\(|%24%28|\|\||%7C%7C|&&|%26%26|;|%3B)") {
- set $block_common_exploits 1;
-}
-
-if ($query_string ~ "(cat|ls|pwd|id|whoami|uname|nc|netcat|wget|curl|ping)\s") {
- set $block_common_exploits 1;
-}
-
-# LDAP injection
-if ($query_string ~ "(\*\)|\(\||\&\(|\|\()") {
- set $block_common_exploits 1;
-}
-
-# XML/XXE attacks
-if ($query_string ~ "(!DOCTYPE|!ENTITY|SYSTEM|PUBLIC|xmlns)") {
- set $block_common_exploits 1;
-}
-
-# Server-side template injection
-if ($query_string ~ "(\{\{|\}\}|\{%|%\}|\$\{|\}$)") {
- set $block_common_exploits 1;
-}
-
-if ($block_common_exploits = 1) {
- return 403;
-}
-
-## Block malicious user agents
-set $block_user_agents 0;
-
-# Original user agents
-# Disable Akeeba Remote Control 2.5 and earlier
-if ($http_user_agent ~ "Indy Library") {
- set $block_user_agents 1;
-}
-
-# Common bandwidth hoggers and hacking tools
-if ($http_user_agent ~ "libwww-perl") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "GetRight") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "GetWeb!") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "Go!Zilla") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "Download Demon") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "Go-Ahead-Got-It") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "TurnitinBot") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "GrabNet") {
- set $block_user_agents 1;
-}
-
-# Enhanced malicious bots and tools
-if ($http_user_agent ~ "(sqlmap|nmap|masscan|zmap|nikto|dirb|dirbuster|gobuster)") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "(havij|pangolin|sqlninja|bbqsql|NoSQLMap|commix)") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "(nessus|openvas|nexpose|metasploit|burpsuite|owasp.zap)") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "(w3af|skipfish|arachni|wpscan|joomscan|cms.scanner)") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "(hydra|brutus|medusa|ncrack|john.ripper|hashcat)") {
- set $block_user_agents 1;
-}
-
-# Scrapers and harvesters
-if ($http_user_agent ~ "(harvest|extract|scrape|spider|crawl|bot).*email") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "(winhttp|urllib|python-requests|curl).*script") {
- set $block_user_agents 1;
-}
-
-# Suspicious patterns
-if ($http_user_agent ~ "^-$|^$|^\.$") {
- set $block_user_agents 1;
-}
-
-if ($http_user_agent ~ "(<|>|\||&|'|\"|;|\$|\(|\)|`|\{|\})") {
- set $block_user_agents 1;
-}
-
-# Common attack frameworks
-if ($http_user_agent ~ "(exploit|payload|shellcode|backdoor|webshell)") {
- set $block_user_agents 1;
-}
-
-if ($block_user_agents = 1) {
- return 403;
-}
-
-## Block suspicious request methods
-set $block_methods 0;
-
-if ($request_method ~ "^(TRACE|TRACK|DEBUG|OPTIONS|CONNECT)$") {
- set $block_methods 1;
-}
-
-if ($block_methods = 1) {
- return 405;
-}
-
-## Block suspicious headers
-set $block_headers 0;
-
-if ($http_x_forwarded_for ~ "(SELECT|INSERT|UPDATE|DELETE|UNION|SCRIPT|IFRAME|OBJECT|EMBED)") {
- set $block_headers 1;
-}
-
-if ($http_referer ~ "(SELECT|INSERT|UPDATE|DELETE|UNION|
-<%- include partials/footer.ejs %>
diff --git a/frontend/html/login.ejs b/frontend/html/login.ejs
deleted file mode 100644
index bc4b9a27..00000000
--- a/frontend/html/login.ejs
+++ /dev/null
@@ -1,9 +0,0 @@
-<% var title = 'Login – Nginx Proxy Manager' %>
-<%- include partials/header.ejs %>
-
-
-
-
-
-
-<%- include partials/footer.ejs %>
diff --git a/frontend/html/partials/footer.ejs b/frontend/html/partials/footer.ejs
deleted file mode 100644
index 7fb2bd61..00000000
--- a/frontend/html/partials/footer.ejs
+++ /dev/null
@@ -1,2 +0,0 @@
-