diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..72036cf --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,83 @@ +# CI/CD Workflows + +## Pull Request Testing + +The `pr-tests.yml` workflow automatically runs on every pull request to the `master` branch. + +### What it does: + +1. **Multi-version testing**: Tests run on Node.js 18.x, 20.x, and 22.x +2. **Comprehensive coverage**: Runs unit tests, integration tests, and full test suite +3. **Blocks merging**: PRs cannot be merged until all tests pass on all Node versions + +### Workflow triggers: + +- Opening a pull request to `master` +- Pushing new commits to an existing PR +- Updates to PR branches + +### Test jobs: + +1. **Unit tests** - Tests isolated components (callback queue, host lookup, unix socket) +2. **Integration tests** - Tests DNS provider contracts +3. **Full test suite** - Complete test coverage + +### Branch protection: + +The `master` branch is protected and requires: +- All tests must pass before merging +- Status check: `test` job must succeed +- Applies to all contributors (admins can override) + +## Running tests locally: + +Before creating a PR, run tests locally to catch issues early: + +```bash +cd nodejs +npm run test:unit # Run unit tests only +npm run test:integration # Run integration tests only +npm test # Run all tests +npm run test:watch # Watch mode for development +``` + +## Adding new workflows: + +To add new CI/CD workflows: + +1. Create a new `.yml` file in `.github/workflows/` +2. Define triggers, jobs, and steps +3. Test the workflow by creating a PR +4. Add status check to branch protection if required for merging + +## Troubleshooting: + +**Tests pass locally but fail in CI:** +- Check Node.js version compatibility (workflow tests 18.x, 20.x, 22.x) +- Verify all dependencies are in package.json (not installed globally) +- Check for environment-specific issues (paths, permissions) + +**Branch protection preventing merge:** +- Ensure all required status checks pass +- Check workflow logs for detailed error messages +- Re-run failed jobs if transient failures occurred + +**Modifying branch protection:** + +```bash +# View current protection settings +gh api repos/theta42/proxy/branches/master/protection + +# Update required status checks +gh api repos/theta42/proxy/branches/master/protection \ + -X PUT \ + -F required_status_checks[contexts][]=test \ + -F required_status_checks[contexts][]=your-new-check +``` + +## Workflow status: + +View workflow runs and status: +- GitHub UI: https://github.com/theta42/proxy/actions +- CLI: `gh run list` +- PR checks: Automatically shown on PR page diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml new file mode 100644 index 0000000..976adf2 --- /dev/null +++ b/.github/workflows/pr-tests.yml @@ -0,0 +1,61 @@ +name: Pull Request Tests + +# Run tests on pull requests to master and when pushing to PRs +on: + pull_request: + branches: + - master + push: + branches-ignore: + - master + +jobs: + test: + name: Run Tests + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [18.x, 20.x, 22.x] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + cache-dependency-path: nodejs/package-lock.json + + - name: Install dependencies + working-directory: ./nodejs + run: npm ci + + - name: Run unit tests + working-directory: ./nodejs + run: npm run test:unit + + - name: Run integration tests + working-directory: ./nodejs + run: npm run test:integration + + - name: Run all tests + working-directory: ./nodejs + run: npm test + + test-summary: + name: Test Summary + runs-on: ubuntu-latest + needs: test + if: always() + + steps: + - name: Check test results + run: | + if [ "${{ needs.test.result }}" != "success" ]; then + echo "Tests failed. PR cannot be merged." + exit 1 + fi + echo "All tests passed successfully!" diff --git a/README.md b/README.md index 40ed0e6..0f42ed8 100755 --- a/README.md +++ b/README.md @@ -1,157 +1,218 @@ -# proxy +# Proxy -A simple reverse proxy and https termination using openresty/nginx with a managment API and GUI. +A reverse proxy and HTTPS termination service using OpenResty/nginx with a management API and web GUI. -## API docs -[API docs](api.md) +**Documentation:** [https://theta42.github.io/proxy/](https://theta42.github.io/proxy/) -## Server set up +## Features -The server requires: -* NodeJS 8.x -* inbound Internet access -* OpenResty -* redis -* lua rocks +- Automated HTTPS/SSL certificate management via Let's Encrypt +- Support for HTTP-01 (auto-ssl) and DNS-01 (wildcard) ACME challenges +- Multiple DNS provider integrations (CloudFlare, DigitalOcean, PorkBun) +- Wildcard SSL certificate support with automatic renewal +- Dynamic host routing with wildcard domain matching (*, **) +- Web-based management interface +- RESTful API for automation +- User authentication and management +- Unix socket-based host lookup for high-performance routing -This has been tested on ubuntu 16.04, but should work on any modern Linux -distro. -**Optional** Linux users for its user management, so this will -**ONLY** work on Linux, no macOS, BSD or Windows and require root. +## Requirements -The steps below are for a new ubuntu server, they should be mostly the same for -other distros, but the paths and availability of packages may vary. A dedicated -server is highly recommended (since it will make ever user a system user), a VPS -like Digital Ocean will do just fine. +- Node.js 18+ (tested with 18.x, 20.x, 22.x) +- OpenResty (nginx with Lua support) +- Redis +- Modern Linux distribution (tested on Ubuntu 20.04+, Debian 11+) +- Inbound internet access for Let's Encrypt validation +- Root access (required for user management features) -* Install openresty +## Quick Install - [OpenResty® Linux Packages](https://openresty.org/en/linux-packages.html) - -* These packages are needed for the PAM node package - - ```bash - apt install libpam0g-dev build-essential - ``` - -* Install redis - - ```bash - apt install redis-server - ``` - -* install lua plugin +An automated installer is available for modern Debian-based systems: ```bash -apt install luarocks -sudo luarocks install lua-resty-auto-ssl -sudo luarocks install lua-resty-socket -sudo luarocks install lua-socket -sudo luarocks install socket -sudo luarocks install luasocket -sudo luarocks install luasocket-unix -sudo luarocks install lua-cjson +wget -O - https://raw.githubusercontent.com/theta42/proxy/master/ops/install.sh | sudo bash ``` -* openresty config +This installer will: +- Install Node.js 20.x +- Install OpenResty and required dependencies +- Install and configure Redis +- Set up SSL fallback certificates +- Install Lua dependencies (lua-resty-auto-ssl, luasocket) +- Clone and install the proxy application +- Configure systemd service +- Start the proxy service -Set up fail back SSL certs +## Manual Installation +For manual installation or other distributions, see the detailed steps below. + +### System Dependencies + +**Ubuntu/Debian:** ```bash -mkdir /etc/ssl/ - -openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj '/CN=sni-support-required-for-valid-ssl' -keyout /etc/ssl/resty-auto-ssl-fallback.key -out /etc/ssl/resty-auto-ssl-fallback.crt - -openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -subj '/CN=sni-support-required-for-valid-ssl' -keyout /etc/ssl/resty-auto-ssl-fallback.key -out /etc/ssl/resty-auto-ssl-fallback.crt - -# openssl dhparam -out /etc/nginx/dhparam.pem 4096 # This takes a LONG time and is not needed. - +apt install libpam0g-dev build-essential redis-server luarocks -y ``` -Change the `/etc/openresty/nginx.conf to have this config` - -``` -#user nobody; -worker_processes 4; - -#error_log logs/error.log; -#error_log logs/error.log notice; -#error_log logs/error.log info; - -#pid logs/nginx.pid; - - -events { - worker_connections 1024; -} - - -http { - client_max_body_size 4g; - - - lua_shared_dict auto_ssl 100m; - lua_shared_dict auto_ssl_settings 64k; - - resolver 8.8.4.4 8.8.8.8; - - init_by_lua_block { - auto_ssl = (require "resty.auto-ssl").new() - auto_ssl:set("storage_adapter", "resty.auto-ssl.storage_adapters.redis") - auto_ssl:set("allow_domain", function(domain) - return true - end) - auto_ssl:init() - } - - init_worker_by_lua_block { - auto_ssl:init_worker() - } - - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 10m; - - server { - listen 127.0.0.1:8999; - - # Increase the body buffer size, to ensure the internal POSTs can always - # parse the full POST contents into memory. - client_body_buffer_size 128k; - client_max_body_size 128k; - - location / { - content_by_lua_block { - auto_ssl:hook_server() - } - } - } - - include mime.types; - default_type application/octet-stream; - - #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - # '$status $body_bytes_sent "$http_referer" ' - # '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log; - error_log /var/log/nginx/error.log; - - sendfile on; - #tcp_nopush on; - - #keepalive_timeout 0; - keepalive_timeout 65; - - #gzip on; - include sites-enabled/*; - -} - +**Node.js 20.x:** +```bash +curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg +NODE_MAJOR=20 +echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list +apt update && apt install nodejs -y ``` -add the SSL config file `/etc/openresty/autossl.conf`, contents from here -https://github.com/theta42/t42-common/blob/master/templates/openresty/autossl.conf.erb +**OpenResty:** +```bash +wget -O - https://openresty.org/package/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/openresty.gpg +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list +apt update && apt install openresty -y +``` +**Lua Dependencies:** +```bash +luarocks install lua-resty-auto-ssl +luarocks install luasocket +``` -Add the proxy config `/etc/openresty/sites-enabled/000-proxy` contents from here -https://github.com/theta42/t42-common/blob/master/templates/openresty/010-proxy.conf.erb +### SSL Configuration + +Create fallback SSL certificates: +```bash +mkdir -p /etc/ssl/ +openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \ + -subj '/CN=sni-support-required-for-valid-ssl' \ + -keyout /etc/ssl/resty-auto-ssl-fallback.key \ + -out /etc/ssl/resty-auto-ssl-fallback.crt +``` + +### OpenResty Configuration + +Configuration files are provided in `ops/nginx_conf/`: +- `nginx.conf` - Main nginx configuration +- `autossl.conf` - Auto-SSL configuration for Let's Encrypt HTTP-01 +- `proxy.conf` - Proxy server configuration with host lookup +- `targetinfo.lua` - Lua module for host lookup via Unix socket + +Copy these files to `/etc/openresty/`: +```bash +mkdir -p /etc/openresty/sites-enabled/ +cp ops/nginx_conf/nginx.conf /etc/openresty/nginx.conf +cp ops/nginx_conf/autossl.conf /etc/openresty/autossl.conf +cp ops/nginx_conf/proxy.conf /etc/openresty/sites-enabled/000-proxy +cp ops/nginx_conf/targetinfo.lua /usr/local/openresty/lualib/targetinfo.lua +``` + +### Application Setup + +Clone and install: +```bash +cd /var/www +git clone https://github.com/theta42/proxy.git +cd proxy/nodejs +npm install +``` + +Create systemd service: +```bash +cp ops/proxy.service /etc/systemd/system/proxy.service +systemctl daemon-reload +systemctl enable proxy.service +systemctl start proxy.service +``` + +## DNS Provider Configuration + +For wildcard SSL certificates, configure a DNS provider via the web UI or API: + +**Supported providers:** +- **CloudFlare** - Requires API token +- **DigitalOcean** - Requires API token +- **PorkBun** - Requires API key and secret API key + +Once configured, create a wildcard host (e.g., `*.example.com`) and the system will automatically request and manage the DNS-01 challenge certificate. + +## Architecture + +The system consists of three main components: + +1. **OpenResty/Nginx** - Frontend proxy with Lua-based routing + - Handles SSL termination via lua-resty-auto-ssl + - Queries Node.js backend via Unix socket for host routing + - Proxies requests to configured backend servers + +2. **Node.js API** - Backend management and control plane + - RESTful API for host/user/DNS management + - Wildcard SSL certificate orchestration + - Host lookup tree with wildcard matching + - User authentication and authorization + +3. **Redis** - Data store + - Host configurations + - User accounts and tokens + - SSL certificate storage + - Domain and DNS provider configurations + +## Host Lookup System + +The proxy supports sophisticated domain matching: +- **Exact match**: `example.com` matches only `example.com` +- **Single wildcard**: `*.example.com` matches `sub.example.com` but not `deep.sub.example.com` +- **Double wildcard**: `**.example.com` matches any depth (`sub.example.com`, `deep.sub.example.com`, etc.) +- **Mixed wildcards**: `api.*.example.com` matches `api.v1.example.com`, `api.v2.example.com`, etc. + +Priority: Exact match > Single wildcard > Double wildcard + +## Development + +**Running locally:** +```bash +cd nodejs +npm install +npm run dev # Runs with nodemon for auto-reload +``` + +**Running tests:** +```bash +npm test # Run all tests +npm run test:unit # Run unit tests only +npm run test:watch # Watch mode for development +``` + +Tests use Node.js built-in test runner (requires Node 18+). + +## API Documentation + +See [API Documentation](nodejs/api.md) for complete API reference. + +## Contributing + +Pull requests are welcome. The project uses GitHub Actions for CI/CD: +- Tests run automatically on all PRs +- All tests must pass before merging to master +- Tests run on Node.js 18.x, 20.x, and 22.x + +## License + +MIT - See LICENSE file for details. + +## Project Structure + +``` +proxy/ +├── nodejs/ # Node.js backend application +│ ├── bin/ # Entry point (www) +│ ├── models/ # Data models (Host, User, DNS providers) +│ ├── routes/ # API routes +│ ├── services/ # Background services (host lookup, scheduler) +│ ├── middleware/ # Express middleware +│ ├── utils/ # Utility functions +│ ├── public/ # Static web assets +│ ├── views/ # EJS templates +│ └── test/ # Test suite +├── ops/ # Operations and deployment +│ ├── nginx_conf/ # OpenResty configuration files +│ ├── install.sh # Automated installer +│ └── proxy.service # Systemd service definition +└── .github/workflows/ # CI/CD workflows +``` diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..e23feb5 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,44 @@ +# Documentation + +This directory contains the GitHub Pages documentation site for the Proxy project. + +**Live site:** https://theta42.github.io/proxy/ + +## Pages + +- `index.md` - Home page with project overview +- `installation.md` - Installation and setup guide +- `api.md` - Complete API reference +- `architecture.md` - System architecture and design +- `contributing.md` - Development and contribution guide + +## Local Preview + +To preview the site locally: + +```bash +# Install Jekyll (one-time setup) +gem install jekyll bundler + +# Run local server +cd docs +jekyll serve + +# View at http://localhost:4000/proxy/ +``` + +## Theme + +The site uses the Cayman theme (`jekyll-theme-cayman`). Configuration is in `_config.yml`. + +## Updating Documentation + +1. Edit markdown files in this directory +2. Commit and push to master branch +3. GitHub Pages automatically rebuilds (may take 1-2 minutes) +4. Changes visible at https://theta42.github.io/proxy/ + +## Legacy Documentation + +- `dev_setup.md` - Old development setup notes (kept for reference) +- `Update 4.11.md` - Old update notes (kept for reference) diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..71c46c3 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,9 @@ +title: Proxy +description: A reverse proxy and HTTPS termination service using OpenResty/nginx with a management API and web GUI +theme: jekyll-theme-cayman +show_downloads: true +github: + repository_url: https://github.com/theta42/proxy + zip_url: https://github.com/theta42/proxy/archive/refs/heads/master.zip + tar_url: https://github.com/theta42/proxy/archive/refs/heads/master.tar.gz + repository_name: theta42/proxy diff --git a/docs/api.md b/docs/api.md new file mode 100755 index 0000000..9ce0536 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,549 @@ +--- +layout: default +title: API Reference +--- + +# API Documentation + +[← Back to Home](index.html) + +All API endpoints require authentication via the `auth-token` header unless otherwise noted. + +Base URL: `https://your-proxy-host.com/api` + +--- + +## Authentication + +### Login + +**POST** `/api/auth/login` + +Authenticate a user and receive an auth token. + +```bash +curl -H "Content-Type: application/json" \ + -X POST \ + -d '{"username": "myuser", "password": "mypassword"}' \ + https://proxy-host.com/api/auth/login +``` + +**Responses:** +- `200` `{"login": true, "token": "027d3964-7d81-4462-a6f9-2c1f9b40b4be", "message": "myuser logged in!"}` +- `401` `{"name": "LoginFailed", "message": "Invalid Credentials, login failed."}` + +### Logout + +**ALL** `/api/auth/logout` + +Invalidate the current auth token. + +```bash +curl -H "auth-token: your-token-here" \ + -X POST \ + https://proxy-host.com/api/auth/logout +``` + +**Responses:** +- `200` `{"message": "Bye"}` + +--- + +## Users + +All user endpoints require authentication. + +### List Users + +**GET** `/api/user` + +Get list of all users. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/user +``` + +**Query Parameters:** +- `detail` - Include full user details (optional) + +**Responses:** +- `200` `{"results": ["user1", "user2"]}` +- `200` `{"results": [{"username": "user1", ...}, ...]}` (with `?detail=true`) + +### Get Current User + +**GET** `/api/user/me` + +Get information about the currently authenticated user. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/user/me +``` + +**Responses:** +- `200` `{"username": "myuser"}` + +### Create User + +**POST** `/api/user` + +Create a new user. + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"username": "newuser", "password": "newpassword"}' \ + https://proxy-host.com/api/user +``` + +**Responses:** +- `200` User created successfully +- `409` Username already exists +- `422` `{"name": "ObjectValidateError", "message": ...}` Validation error + +### Delete User + +**DELETE** `/api/user/:username` + +Delete a user account. + +```bash +curl -H "auth-token: your-token-here" \ + -X DELETE \ + https://proxy-host.com/api/user/olduser +``` + +**Responses:** +- `200` `{"username": "olduser", "results": ...}` +- `404` User not found + +### Change Password (Self) + +**PUT** `/api/user/password` + +Change the password for the currently authenticated user. + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X PUT \ + -d '{"password": "newpassword"}' \ + https://proxy-host.com/api/user/password +``` + +**Responses:** +- `200` `{"results": ...}` Password changed successfully + +### Change Password (Other User) + +**PUT** `/api/user/password/:username` + +Change the password for another user (admin function). + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X PUT \ + -d '{"password": "newpassword"}' \ + https://proxy-host.com/api/user/password/otheruser +``` + +**Responses:** +- `200` `{"results": ...}` Password changed successfully +- `404` User not found + +### Create Invite Token + +**POST** `/api/user/invite` + +Create an invitation token for new user registration. + +```bash +curl -H "auth-token: your-token-here" \ + -X POST \ + https://proxy-host.com/api/user/invite +``` + +**Responses:** +- `200` `{"token": "5caf94d2-2c91-4010-8df7-968d10802b9d"}` + +### Add SSH Key + +**POST** `/api/user/key` + +Add an SSH public key to the current user's account. + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"key": "ssh-rsa AAAAB3..."}' \ + https://proxy-host.com/api/user/key +``` + +**Responses:** +- `200` `{"message": true}` Key added successfully +- `400` `{"message": "Bad SSH key"}` Invalid key format + +--- + +## Hosts + +Manage proxy host configurations. + +### List Hosts + +**GET** `/api/host` + +Get list of all configured hosts. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/host +``` + +**Query Parameters:** +- `detail` - Include full host details (optional) + +**Responses:** +- `200` `{"results": ["example.com", "*.wildcard.com"]}` +- `200` `{"results": [{"host": "example.com", "ip": "192.168.1.10", ...}, ...]}` (with `?detail=true`) + +### Get Host + +**GET** `/api/host/:host` + +Get configuration for a specific host. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/host/example.com +``` + +**Responses:** +- `200` `{"item": "example.com", "results": {"host": "example.com", "ip": "192.168.1.10", "targetPort": 8080, ...}}` +- `404` `{"name": "HostNotFound", "message": "Host does not exists"}` + +### Lookup Host + +**GET** `/api/host/lookup/:domain` + +Test the host lookup algorithm (supports wildcard matching). + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/host/lookup/sub.example.com +``` + +**Responses:** +- `200` `{"string": "sub.example.com", "results": {"host": "*.example.com", ...}}` +- `200` `{"string": "sub.example.com", "results": null}` (no match) + +### Get Lookup Tree + +**GET** `/api/host/lookupobj` + +Get the internal lookup tree structure (for debugging). + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/host/lookupobj +``` + +**Responses:** +- `200` `{"results": {"com": {"example": {...}}}}` + +### Create Host + +**POST** `/api/host` + +Add a new host configuration. + +**Parameters:** +- `host` (required) - Domain name (e.g., `example.com`, `*.example.com`) +- `ip` (required) - Target IP address or FQDN +- `targetPort` (required) - Target port number (1-65535) +- `forcessl` (optional) - Force HTTPS redirect (default: true) +- `targetssl` (optional) - Use HTTPS to backend (default: false) +- `challengeType` (optional) - For wildcards: `DNS-01-wildcard` or `wildcardChild` + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"host": "example.com", "ip": "192.168.1.10", "targetPort": 8080, "forcessl": true, "targetssl": false}' \ + https://proxy-host.com/api/host +``` + +**Responses:** +- `200` `{"message": "\"example.com\" added.", "host": "example.com", ...}` +- `409` `{"name": "HostNameUsed", "message": "Host already exists"}` +- `422` `{"name": "ObjectValidateError", "message": ...}` Validation error + +### Update Host + +**PUT** `/api/host/:host` + +Update an existing host configuration. + +**Parameters:** Same as Create Host (all optional) + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X PUT \ + -d '{"ip": "192.168.1.20", "targetPort": 9000}' \ + https://proxy-host.com/api/host/example.com +``` + +**Responses:** +- `200` `{"message": "\"example.com\" updated.", ...}` +- `404` `{"name": "HostNotFound", "message": "Host does not exists"}` +- `422` Validation error + +### Delete Host + +**DELETE** `/api/host/:host` + +Remove a host configuration. + +```bash +curl -H "auth-token: your-token-here" \ + -X DELETE \ + https://proxy-host.com/api/host/example.com +``` + +**Responses:** +- `200` `{"message": "example.com deleted", ...}` +- `404` `{"name": "HostNotFound", "message": "Host does not exists"}` + +### Renew Wildcard Certificate + +**PUT** `/api/host/:host/renew` + +Manually trigger wildcard certificate renewal. + +```bash +curl -H "auth-token: your-token-here" \ + -X PUT \ + https://proxy-host.com/api/host/*.example.com/renew +``` + +**Responses:** +- `200` `{"message": "Requesting wildcard cert for *.example.com"}` +- `404` Host not found + +--- + +## DNS Providers + +Manage DNS provider integrations for wildcard SSL certificates. + +### List DNS Providers + +**GET** `/api/dns` + +Get list of configured DNS providers. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/dns +``` + +**Query Parameters:** +- `detail` - Include full provider details (optional) + +**Responses:** +- `200` `{"results": ["provider-id-1", "provider-id-2"]}` + +### List Available Provider Types + +**OPTIONS** `/api/dns` + +Get list of supported DNS provider types and their configuration requirements. + +```bash +curl -H "auth-token: your-token-here" \ + -X OPTIONS \ + https://proxy-host.com/api/dns +``` + +**Responses:** +- `200` `{"results": [{"name": "CloudFlare", "fields": {...}}, {"name": "DigitalOcean", ...}, ...]}` + +### Create DNS Provider + +**POST** `/api/dns` + +Configure a new DNS provider. + +**CloudFlare:** +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"name": "My CloudFlare", "dnsProvider": "Cloudflare", "token": "your-api-token"}' \ + https://proxy-host.com/api/dns +``` + +**DigitalOcean:** +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"name": "My DO", "dnsProvider": "DigitalOcean", "token": "your-api-token"}' \ + https://proxy-host.com/api/dns +``` + +**PorkBun:** +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"name": "My PorkBun", "dnsProvider": "PorkBun", "apiKey": "pk_xxx", "secretApiKey": "sk_xxx"}' \ + https://proxy-host.com/api/dns +``` + +**Responses:** +- `200` `{"message": "\"provider-id\" added.", ...}` +- `422` Validation error or invalid API credentials + +### Get DNS Provider + +**GET** `/api/dns/:id` + +Get a specific DNS provider configuration. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/dns/provider-id +``` + +**Responses:** +- `200` `{"item": "provider-id", "results": {...}}` +- `404` Provider not found + +### Update DNS Provider + +**PUT** `/api/dns/:id` + +Update DNS provider configuration. + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X PUT \ + -d '{"name": "Updated Name"}' \ + https://proxy-host.com/api/dns/provider-id +``` + +**Responses:** +- `200` `{"message": "\"provider-id\" updated.", ...}` +- `404` Provider not found + +### Delete DNS Provider + +**DELETE** `/api/dns/:id` + +Remove a DNS provider and all associated domains. + +```bash +curl -H "auth-token: your-token-here" \ + -X DELETE \ + https://proxy-host.com/api/dns/provider-id +``` + +**Responses:** +- `200` `{"message": "provider-id deleted", ...}` +- `404` Provider not found + +### List Domains + +**GET** `/api/dns/domain` + +List all domains from all configured providers. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/dns/domain +``` + +**Query Parameters:** +- `detail` - Include full domain details (optional) + +**Responses:** +- `200` `{"results": ["example.com", "test.com"]}` + +### Get Domain + +**GET** `/api/dns/domain/:domain` + +Get details for a specific domain. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/dns/domain/example.com +``` + +**Responses:** +- `200` `{"results": [{"domain": "example.com", "zoneId": "...", ...}]}` +- `404` Domain not found + +### Refresh Domains + +**POST** `/api/dns/domain/refresh/:providerId` + +Refresh the domain list from a DNS provider's API. + +```bash +curl -H "auth-token: your-token-here" \ + -X POST \ + https://proxy-host.com/api/dns/domain/refresh/provider-id +``` + +**Responses:** +- `200` `{"results": ...}` Updated domain list +- `404` Provider not found + +--- + +## Certificates + +Retrieve SSL certificate information. + +### Get Certificate + +**GET** `/api/cert/:host` + +Get the SSL certificate for a host. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/cert/example.com +``` + +**Responses:** +- `200` Certificate data including `cert_pem`, `fullchain_pem`, `privkey_pem`, expiry information +- `404` Certificate not found + +--- + +## Error Responses + +All endpoints may return the following error responses: + +- `401` `{"name": "LoginFailed", "message": "Invalid Credentials, login failed."}` - Authentication required or invalid +- `404` `{"name": "NotFound", "message": "..."}` - Resource not found +- `422` `{"name": "ObjectValidateError", "message": [...], "keys": [...]}` - Validation errors +- `500` Internal server error + +## Notes + +- All timestamps are in milliseconds since epoch +- The `auth-token` header is required for all authenticated endpoints +- Host names support wildcards: `*` (single level) and `**` (multi-level) +- DNS providers are validated on creation - invalid API credentials will be rejected +- Wildcard certificates are automatically renewed 30 days before expiration diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..36f18de --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,265 @@ +--- +layout: default +title: Architecture +--- + +# Architecture + +[← Back to Home](index.html) + +## System Overview + +The proxy system consists of three main components working together to provide high-performance reverse proxying with automated SSL management. + +``` +┌──────────────────────────────────────────────────────────────┐ +│ Internet │ +└─────────────────────────┬────────────────────────────────────┘ + │ HTTPS/HTTP + ▼ +┌──────────────────────────────────────────────────────────────┐ +│ OpenResty/Nginx │ +│ ┌────────────────┐ ┌──────────────┐ ┌─────────────────┐ │ +│ │ SSL Termination│ │ Host Routing │ │ Request Proxying│ │ +│ │ (lua-resty- │ │ (targetinfo. │ │ │ │ +│ │ auto-ssl) │ │ lua) │ │ │ │ +│ └────────────────┘ └──────────────┘ └─────────────────┘ │ +└────────────┬──────────────────┬───────────────────────────┬──┘ + │ │ │ + Let's Encrypt Unix Socket Backend + HTTP-01 Lookup Query Services + │ │ │ + ▼ ▼ ▼ +┌──────────────────────────────────────────────────────────────┐ +│ Node.js Application │ +│ ┌──────────────┐ ┌────────────────┐ ┌─────────────────┐ │ +│ │ Services │ │ Models │ │ Routes │ │ +│ │ - host_lookup│ │ - Host │ │ - /api/host │ │ +│ │ - scheduler │ │ - DNS Provider │ │ - /api/dns │ │ +│ └──────────────┘ │ - User │ │ - /api/user │ │ +│ │ - Auth │ │ - /api/auth │ │ +│ └────────────────┘ │ - /api/cert │ │ +│ └─────────────────┘ │ +└────────────┬────────────────────┬────────────────────────────┘ + │ │ + ▼ ▼ +┌──────────────────────┐ ┌──────────────────────┐ +│ Redis │ │ DNS Providers │ +│ - Host configs │ │ - CloudFlare │ +│ - User accounts │ │ - DigitalOcean │ +│ - SSL certs │ │ - PorkBun │ +│ - Auth tokens │ │ (DNS-01 challenges) │ +└──────────────────────┘ └──────────────────────┘ +``` + +## Component Details + +### OpenResty/Nginx (Frontend) + +**Responsibilities:** +- Accept incoming HTTP/HTTPS requests +- SSL termination using lua-resty-auto-ssl +- Host-based routing decisions +- Proxy requests to backend services + +**Key Features:** +- HTTP-01 ACME challenge handling for automatic SSL +- Lua-based host lookup via Unix socket +- High-performance event-driven architecture +- Support for WebSocket connections + +**Configuration Files:** +- `/etc/openresty/nginx.conf` - Main configuration +- `/etc/openresty/autossl.conf` - Let's Encrypt integration +- `/etc/openresty/sites-enabled/000-proxy` - Proxy configuration +- `/usr/local/openresty/lualib/targetinfo.lua` - Host lookup module + +### Node.js Application (Backend) + +**Responsibilities:** +- API for host/user/DNS management +- Wildcard SSL certificate orchestration +- Host lookup tree maintenance +- User authentication and authorization + +**Directory Structure:** +``` +nodejs/ +├── bin/www # Application entry point +├── models/ # Data models +│ ├── host.js # Host configuration and lookup +│ ├── auth.js # Authentication logic +│ ├── user.js # User management +│ └── dns_provider/ # DNS provider implementations +├── routes/ # API endpoints +│ ├── host.js # Host CRUD operations +│ ├── dns.js # DNS provider management +│ ├── user.js # User management +│ └── auth.js # Authentication +├── services/ # Background services +│ ├── host_lookup.js # Unix socket server +│ └── host_scheduler.js # Cert renewal scheduler +├── middleware/ # Express middleware +│ └── auth.js # Authentication middleware +└── utils/ # Utility modules + └── unix_socket_json.js # Unix socket server +``` + +### Redis (Data Store) + +**Stored Data:** +- Host configurations (domain, IP, port, SSL settings) +- User accounts and hashed passwords +- Authentication tokens +- SSL certificates (for wildcard domains) +- DNS provider credentials +- Domain-to-provider mappings + +**Key Prefixes:** +``` +proxy_Host_ # Host configuration +proxy_User_ # User account +proxy_AuthToken_ # Auth tokens +proxy_DnsProvider_ # DNS provider +proxy_Domain_ # Domain info +:latest # SSL certificate cache +``` + +## Request Flow + +### Standard HTTP/HTTPS Request + +1. **Client** sends HTTPS request to `app.example.com` +2. **OpenResty** receives request, terminates SSL +3. **Lua script** (`targetinfo.lua`) queries Redis for host config +4. If **cache miss**, Lua queries Node.js via Unix socket +5. **Node.js** performs host lookup (supports wildcards) +6. **Response** returned with target IP and port +7. **OpenResty** proxies request to backend service +8. **Response** proxied back to client + +### Wildcard SSL Certificate Request + +1. **User** creates wildcard host (`*.example.com`) via API +2. **Node.js** validates domain has DNS provider configured +3. **Let's Encrypt** DNS-01 challenge initiated +4. **DNS provider** API creates TXT record (`_acme-challenge.example.com`) +5. **Let's Encrypt** validates TXT record +6. **Certificate** generated and stored in Redis +7. **DNS provider** cleans up TXT record +8. **Background scheduler** monitors expiration, renews 30 days before expiry + +## Host Lookup Algorithm + +The lookup tree enables sophisticated domain matching: + +``` +Input: "api.v1.example.com" + +Tree Structure: +{ + "com": { + "example": { + "*": { // Matches api.example.com + "#record": {...} + }, + "v1": { + "api": { // Matches api.v1.example.com (exact) + "#record": {...} + } + } + } + } +} + +Priority: Exact > Single wildcard (*) > Double wildcard (**) +``` + +**Wildcard Types:** +- `example.com` - Exact match only +- `*.example.com` - Matches `sub.example.com` (single level) +- `**.example.com` - Matches any depth (`sub.deep.example.com`) +- `api.*.example.com` - Matches `api.v1.example.com`, `api.v2.example.com` + +## Security Architecture + +### Authentication Flow + +1. User sends credentials to `/api/auth/login` +2. Credentials validated against stored hash (bcrypt) +3. Token generated and stored in Redis with TTL +4. Token returned to client +5. Subsequent requests include token in `auth-token` header +6. Middleware validates token before processing request + +### SSL Certificate Security + +- **Private keys** stored only in Redis (memory/disk based on config) +- **Fallback certificates** used when SNI unavailable +- **Let's Encrypt** rate limiting respected +- **DNS provider credentials** marked as `isPrivate` (not returned in API) + +### Unix Socket Communication + +- Socket file: `/var/run/proxy_lookup.socket` +- Permissions: `777` (container-safe, single-use deployment) +- Protocol: JSON over Unix stream socket +- Buffer handling: Accumulates partial messages until complete JSON + +## Performance Optimizations + +### Caching Strategy + +1. **Redis cache** - Primary host configuration storage +2. **Lookup tree** - In-memory host lookup (rebuilt on changes) +3. **OpenResty cache** - Reduces Unix socket calls +4. **Wildcard parent caching** - Stores resolved wildcard parents + +### Unix Socket vs HTTP API + +Unix socket chosen over HTTP for host lookups: +- **Lower latency** - No TCP overhead +- **Higher throughput** - No HTTP parsing +- **Simpler** - Direct JSON communication +- **Secure** - Filesystem permissions, no network exposure + +## Scalability Considerations + +### Current Architecture + +- **Single instance** - OpenResty + Node.js + Redis on one server +- **Vertical scaling** - Add CPU/RAM as needed +- **Limitations** - Unix socket ties OpenResty to Node.js on same host + +### Future Scaling Options + +- **Redis cluster** - Distribute data storage +- **Multiple OpenResty instances** - Load balance incoming requests +- **Stateless Node.js** - Run multiple API instances +- **Replace Unix socket** - Use TCP/HTTP for cross-host communication +- **Separate cert management** - Dedicated service for wildcard SSL + +## Monitoring and Observability + +### Logs + +- **OpenResty**: `/var/log/nginx/access.log`, `/var/log/nginx/error.log` +- **Node.js**: `journalctl -u proxy.service` +- **Redis**: `redis-cli MONITOR` + +### Health Checks + +- Node.js API: `curl http://localhost:3000/api/host` +- Redis: `redis-cli PING` +- OpenResty: `systemctl status openresty` +- Unix socket: `ls -la /var/run/proxy_lookup.socket` + +### Metrics to Monitor + +- Request rate and response times +- SSL certificate expiration dates +- Redis memory usage +- Host lookup cache hit rate +- Background service execution times + +[← Back to Home](index.html) diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..76ef5a3 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,308 @@ +--- +layout: default +title: Contributing +--- + +# Contributing Guide + +[← Back to Home](index.html) + +Thank you for considering contributing to the Proxy project! This guide will help you get started. + +## Development Setup + +### Prerequisites + +- Node.js 18+ (18.x, 20.x, or 22.x recommended) +- Redis server +- Git + +### Local Development + +1. **Clone the repository** + ```bash + git clone https://github.com/theta42/proxy.git + cd proxy/nodejs + ``` + +2. **Install dependencies** + ```bash + npm install + ``` + +3. **Start Redis** (if not already running) + ```bash + redis-server + ``` + +4. **Run in development mode** + ```bash + npm run dev + ``` + + This starts the Node.js API with nodemon for auto-reload on file changes. + +5. **Access the API** + - API: `http://localhost:3000/api` + - Web UI: `http://localhost:3000` + +## Testing + +The project uses Node.js built-in test runner (requires Node 18+). + +### Running Tests + +```bash +# Run all tests +npm test + +# Run only unit tests +npm run test:unit + +# Run only integration tests +npm run test:integration + +# Watch mode for development +npm run test:watch +``` + +### Test Structure + +``` +test/ +├── unit/ # Unit tests for isolated components +│ ├── callback_queue.test.js +│ ├── host_lookup.test.js +│ └── unix_socket.test.js +├── integration/ # Integration tests +│ └── dns_provider.test.js +└── helpers/ # Test utilities + └── dns_provider_contract.js +``` + +### Writing Tests + +We test **custom logic**, not third-party libraries: + +**DO test:** +- Host lookup algorithm +- Socket buffering logic +- DNS provider contracts +- Custom utility functions + +**DON'T test:** +- Express.js routing +- Redis ORM +- External DNS APIs (use mocks instead) + +### Adding DNS Provider Tests + +When adding a new DNS provider, you **must** add contract tests: + +```javascript +describe('NewProvider Provider', () => { + const NewProvider = require('../../models/dns_provider/newprovider'); + + test('should meet DNS provider contract', () => { + const mockCredentials = {api_key: 'mock-key'}; + const instance = validateDnsProviderContract(NewProvider, mockCredentials); + assert.ok(instance); + }); + + test('should have valid method signatures', () => { + const instance = new NewProvider({api_key: 'mock'}); + validateMethodSignatures(instance); + }); + + test('should validate key mapping', () => { + const instance = new NewProvider({api_key: 'mock'}); + validateKeyMapping(instance); + }); + + test('should validate type checking', () => { + const instance = new NewProvider({api_key: 'mock'}); + validateTypeChecking(instance); + }); +}); +``` + +See `test/integration/dns_provider.test.js` for examples. + +## Code Style + +### General Guidelines + +- Use strict mode: `'use strict';` +- Use tabs for indentation +- Clear, descriptive variable names +- Comment complex logic +- No trailing whitespace + +### File Organization + +```javascript +'use strict'; + +// 1. Node.js built-ins +const fs = require('fs'); +const path = require('path'); + +// 2. Third-party modules +const express = require('express'); +const redis = require('redis'); + +// 3. Local modules +const {Host} = require('./models'); +const middleware = require('./middleware/auth'); + +// 4. Code... +``` + +### Naming Conventions + +- Classes: `PascalCase` +- Functions: `camelCase` +- Constants: `UPPER_SNAKE_CASE` +- Private methods: `__privateMethod` (double underscore prefix) + +## Project Structure + +Understanding the codebase: + +``` +nodejs/ +├── models/ # Data models (Host, User, DNS providers) +├── routes/ # API route handlers +├── services/ # Background services (lookup, scheduler) +├── middleware/ # Express middleware +├── utils/ # Utility functions +├── public/ # Static web assets +├── views/ # EJS templates +└── test/ # Test suite +``` + +## Pull Request Process + +### Before Submitting + +1. **Run tests** - Ensure all tests pass + ```bash + npm test + ``` + +2. **Test locally** - Verify your changes work + ```bash + npm run dev + ``` + +3. **Update documentation** - Keep docs in sync with code changes + +4. **Commit messages** - Use clear, descriptive messages + ``` + Add DNS provider for Route53 + + - Implement Route53 DNS API client + - Add contract tests for Route53 + - Update documentation with Route53 setup + ``` + +### Submitting a PR + +1. **Fork the repository** + +2. **Create a feature branch** + ```bash + git checkout -b feature/my-new-feature + ``` + +3. **Make your changes** + +4. **Commit your changes** + ```bash + git add . + git commit -m "Description of changes" + ``` + +5. **Push to your fork** + ```bash + git push origin feature/my-new-feature + ``` + +6. **Open a Pull Request** on GitHub + +### PR Requirements + +- ✅ All tests must pass (CI/CD runs automatically) +- ✅ Tests run on Node.js 18.x, 20.x, and 22.x +- ✅ No merge conflicts with `master` +- ✅ Code follows project conventions +- ✅ New features include tests +- ✅ Documentation updated if needed + +### CI/CD Process + +When you open a PR: +1. GitHub Actions automatically runs tests +2. Tests execute on multiple Node.js versions +3. PR cannot be merged until all checks pass +4. Review from maintainers +5. Merge to master + +## Adding Features + +### Adding a DNS Provider + +1. **Create provider file** in `models/dns_provider/yourprovider.js` + +2. **Extend DnsApi base class** + ```javascript + const {DnsApi} = require('./common'); + + class YourProvider extends DnsApi { + static _keyMap = { + api_key: {isRequired: true, type: 'string', isPrivate: true} + }; + + // Implement required methods + async listDomains() { } + async getRecords(domain, options) { } + async createRecord(domain, options) { } + async deleteRecords(domain, options) { } + } + ``` + +3. **Add to provider list** in `models/dns_provider.js` + +4. **Add contract tests** in `test/integration/dns_provider.test.js` + +5. **Test your provider** + ```bash + npm run test:integration + ``` + +### Adding API Endpoints + +1. **Add route** in appropriate file (`routes/`) +2. **Update API documentation** (`nodejs/api.md`) +3. **Test the endpoint** manually and add integration tests if needed + +## Getting Help + +- **Questions?** Open a [GitHub Discussion](https://github.com/theta42/proxy/discussions) +- **Bug reports** Use [GitHub Issues](https://github.com/theta42/proxy/issues) +- **Security issues** Email maintainers directly (see package.json) + +## Code of Conduct + +- Be respectful and inclusive +- Focus on constructive feedback +- Help others learn and grow +- Follow the project's technical direction + +## License + +By contributing, you agree that your contributions will be licensed under the MIT License. + +--- + +[← Back to Home](index.html) | [View on GitHub](https://github.com/theta42/proxy) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..f607f5b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,97 @@ +--- +layout: default +title: Home +--- + +# Proxy + +A reverse proxy and HTTPS termination service using OpenResty/nginx with a management API and web GUI. + +## Features + +- **Automated HTTPS/SSL** - Let's Encrypt integration with HTTP-01 and DNS-01 challenges +- **Wildcard SSL Certificates** - Support for wildcard domains with automatic renewal +- **Multiple DNS Providers** - CloudFlare, DigitalOcean, PorkBun integrations +- **Advanced Routing** - Sophisticated wildcard domain matching (*, **) +- **RESTful API** - Full programmatic control +- **Web Interface** - User-friendly management GUI +- **High Performance** - Unix socket-based host lookup for minimal latency + +## Quick Start + +### Automated Installation + +For modern Debian-based systems (Ubuntu 20.04+, Debian 11+): + +```bash +wget -O - https://raw.githubusercontent.com/theta42/proxy/master/ops/install.sh | sudo bash +``` + +### Requirements + +- Node.js 18+ (tested with 18.x, 20.x, 22.x) +- OpenResty (nginx with Lua support) +- Redis +- Linux system with root access + +## Documentation + +- [Installation Guide](installation.html) - Detailed setup instructions +- [API Reference](api.html) - Complete API documentation +- [Architecture](architecture.html) - System design and components +- [Contributing](contributing.html) - Development and testing guide + +## Use Cases + +**Development Teams** +- Host multiple projects on a single server with unique domains +- Automatic SSL for all development sites +- Easy configuration via API or web UI + +**Production Deployments** +- High-performance reverse proxy for microservices +- Centralized SSL certificate management +- Dynamic routing without nginx reloads + +**Personal Projects** +- Self-hosted services with automatic HTTPS +- Wildcard certificates for unlimited subdomains +- Simple management interface + +## Architecture + +``` +┌─────────────┐ +│ Client │ +└──────┬──────┘ + │ HTTPS + ▼ +┌─────────────────────┐ +│ OpenResty/Nginx │ +│ - SSL Termination │ +│ - Host Routing │ +└──────┬──────────────┘ + │ Unix Socket + ▼ +┌─────────────────────┐ ┌─────────────┐ +│ Node.js API │◄────►│ Redis │ +│ - Management │ │ - Storage │ +│ - SSL Orchestration│ │ - Cache │ +└──────┬──────────────┘ └─────────────┘ + │ + ▼ +┌─────────────────────┐ +│ Backend Services │ +│ - Your Apps │ +└─────────────────────┘ +``` + +## Community + +- [GitHub Repository](https://github.com/theta42/proxy) +- [Issue Tracker](https://github.com/theta42/proxy/issues) +- [Pull Requests](https://github.com/theta42/proxy/pulls) + +## License + +MIT License - See [LICENSE](https://github.com/theta42/proxy/blob/master/LICENSE) for details. diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..b05f6b7 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,221 @@ +--- +layout: default +title: Installation +--- + +# Installation Guide + +[← Back to Home](index.html) + +## Quick Install (Recommended) + +For modern Debian-based systems (Ubuntu 20.04+, Debian 11+): + +```bash +wget -O - https://raw.githubusercontent.com/theta42/proxy/master/ops/install.sh | sudo bash +``` + +This automated installer will: +- Install Node.js 20.x +- Install OpenResty and required dependencies +- Install and configure Redis +- Set up SSL fallback certificates +- Install Lua dependencies +- Clone and install the proxy application +- Configure systemd service +- Start the proxy service + +## Manual Installation + +### System Requirements + +- Modern Linux distribution (Ubuntu 20.04+, Debian 11+, or equivalent) +- Root access +- Inbound internet access for Let's Encrypt validation +- Minimum 1GB RAM, 10GB disk space + +### Step 1: Install Dependencies + +**Ubuntu/Debian:** +```bash +apt install libpam0g-dev build-essential redis-server luarocks -y +``` + +### Step 2: Install Node.js 20.x + +```bash +curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | \ + sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg + +NODE_MAJOR=20 +echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | \ + sudo tee /etc/apt/sources.list.d/nodesource.list + +apt update && apt install nodejs -y +``` + +Verify installation: +```bash +node --version # Should show v20.x.x +npm --version +``` + +### Step 3: Install OpenResty + +```bash +wget -O - https://openresty.org/package/pubkey.gpg | \ + sudo gpg --dearmor -o /usr/share/keyrings/openresty.gpg + +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/ubuntu $(lsb_release -sc) main" | \ + sudo tee /etc/apt/sources.list.d/openresty.list + +apt update && apt install openresty -y +``` + +### Step 4: Install Lua Dependencies + +```bash +luarocks install lua-resty-auto-ssl +luarocks install luasocket +``` + +### Step 5: SSL Configuration + +Create fallback SSL certificates: + +```bash +mkdir -p /etc/ssl/ + +openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \ + -subj '/CN=sni-support-required-for-valid-ssl' \ + -keyout /etc/ssl/resty-auto-ssl-fallback.key \ + -out /etc/ssl/resty-auto-ssl-fallback.crt +``` + +### Step 6: Configure OpenResty + +Clone the repository and copy configuration files: + +```bash +cd /var/www +git clone https://github.com/theta42/proxy.git +cd proxy + +# Copy nginx configs +mkdir -p /etc/openresty/sites-enabled/ +cp ops/nginx_conf/nginx.conf /etc/openresty/nginx.conf +cp ops/nginx_conf/autossl.conf /etc/openresty/autossl.conf +cp ops/nginx_conf/proxy.conf /etc/openresty/sites-enabled/000-proxy +cp ops/nginx_conf/targetinfo.lua /usr/local/openresty/lualib/targetinfo.lua +``` + +### Step 7: Install Application + +```bash +cd /var/www/proxy/nodejs +npm install +``` + +### Step 8: Configure Systemd Service + +```bash +cp /var/www/proxy/ops/proxy.service /etc/systemd/system/proxy.service +systemctl daemon-reload +systemctl enable proxy.service +systemctl start proxy.service +``` + +Verify service is running: +```bash +systemctl status proxy.service +``` + +### Step 9: Initial Setup + +The proxy API will be available on port 3000 by default. You'll need to: + +1. Create your first user account +2. Configure DNS providers (for wildcard SSL) +3. Add your first host + +See the [API Reference](api.html) for details. + +## Configuration + +### Environment Variables + +- `NODE_ENV` - Set to `production` for production deployments +- `NODE_PORT` - Override default port (default: 3000) + +### Redis Configuration + +The proxy uses Redis with the prefix `proxy_`. To change this, edit `nodejs/conf/base.js`: + +```javascript +redis: { + prefix: 'proxy_' +} +``` + +### OpenResty Configuration + +Key configuration files in `/etc/openresty/`: +- `nginx.conf` - Main nginx configuration +- `autossl.conf` - Let's Encrypt HTTP-01 challenge handler +- `sites-enabled/000-proxy` - Proxy server configuration + +### Unix Socket + +The proxy communicates with OpenResty via Unix socket at: +``` +/var/run/proxy_lookup.socket +``` + +This path is configurable in `nodejs/conf/base.js`. + +## Troubleshooting + +### Service won't start + +Check logs: +```bash +journalctl -u proxy.service -f +``` + +Common issues: +- Port 3000 already in use +- Redis not running: `systemctl status redis-server` +- Permission issues: Service must run as root for user management + +### SSL certificates not working + +Check OpenResty logs: +```bash +tail -f /var/log/nginx/error.log +``` + +Common issues: +- Firewall blocking ports 80/443 +- DNS not pointing to server +- Let's Encrypt rate limits exceeded + +### Host lookup not working + +Check Unix socket: +```bash +ls -la /var/run/proxy_lookup.socket +# Should show srwxrwxrwx (socket permissions) +``` + +Test lookup: +```bash +echo '{"domain":"example.com"}' | nc -U /var/run/proxy_lookup.socket +``` + +## Next Steps + +- [Configure DNS Providers](api.html#dns-providers) for wildcard SSL +- [Add your first host](api.html#hosts) +- [Set up the web interface](index.html) + +[← Back to Home](index.html) diff --git a/nodejs/api.md b/nodejs/api.md index 8c7df99..f354ec4 100755 --- a/nodejs/api.md +++ b/nodejs/api.md @@ -1,132 +1,542 @@ -## get host info +# API Documentation -**GET** `/api/hosts` +All API endpoints require authentication via the `auth-token` header unless otherwise noted. + +Base URL: `https://your-proxy-host.com/api` + +--- + +## Authentication + +### Login + +**POST** `/api/auth/login` + +Authenticate a user and receive an auth token. ```bash -curl -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" https://proxy-host.com/api/hostsmine.com +curl -H "Content-Type: application/json" \ + -X POST \ + -d '{"username": "myuser", "password": "mypassword"}' \ + https://proxy-host.com/api/auth/login ``` -* 200 {"host":"yours.com","results":{"ip":"127.0.0.1:4000","updated":"1518595297563","username":"test10","forceSSL": false, "targetSSL": true, "targetPort": "443"}} -* 404 {"name": "HostNotFound", "message": "Host does not exists"} +**Responses:** +- `200` `{"login": true, "token": "027d3964-7d81-4462-a6f9-2c1f9b40b4be", "message": "myuser logged in!"}` +- `401` `{"name": "LoginFailed", "message": "Invalid Credentials, login failed."}` +### Logout -## view all hosts +**ALL** `/api/auth/logout` -**GET** `/api/hosts` +Invalidate the current auth token. ```bash -curl -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" https://proxy-host.com/api/hosts +curl -H "auth-token: your-token-here" \ + -X POST \ + https://proxy-host.com/api/auth/logout ``` -* 200 {"hosts":["mine.com","mine2.com"]} +**Responses:** +- `200` `{"message": "Bye"}` +--- -## Add host +## Users -**POST** `/api/hosts` +All user endpoints require authentication. -Params -* **host** -- Required, The domain name for the new record. -* **ip** -- Required, The target IP or FQDN for the record. -* **targetSSL** -- If the remote IP target is SSL. Default is false and this is -not recommended. -* **targetPort** -- Required, TCP port for the remote server. Unless you know -otherwise, 80 for targetSSL false and 443 for true. -* **forceSSL** -- If requests should be forced to use SSL from the client to -the proxy. The default is false and this is HIGHLY recommended. -* ** +### List Users + +**GET** `/api/user` + +Get list of all users. ```bash -curl -H "Content-Type: application/json" -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" -X POST -d '{"host": "test.vm42.com", "ip": "192.168.1.21", "targetSSL": false, "targetPort": "443", "forceSSL": true} https://proxy-host.com/api/hosts +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/user ``` -* 200 {"message":"Host yours.com added."} -* 409 {"name":"HostNameUsed", "message":"Host already exists"} -* 422 {"name":"ObjectValidateError","message":[{"key":"ip","message":"ip is required."}]} Missing or incorrect keys/values. Returns a list with a message per key error. +**Query Parameters:** +- `detail` - Include full user details (optional) -## Edit +**Responses:** +- `200` `{"results": ["user1", "user2"]}` +- `200` `{"results": [{"username": "user1", ...}, ...]}` (with `?detail=true`) -**PUT** `/api/hosts` +### Get Current User -Takes the same params as add, but none are required +**GET** `/api/user/me` -curl -H "Content-Type: application/json" -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" -X POST -d '{"host": "test.vm42.com", "ip": "192.168.1.21", "targetSSL": false, "targetPort": "443", "forceSSL": true} https://proxy-host.com/api/hosts - -* 200 {"message":"Host yours.com updated."} -* 404 {"name": "HostNotFound", "message": "Host does not exists"} -* 409 {"name":"HostNameUsed", "message":"Host already exists"} -* 422 {"name":"ObjectValidateError","message":[{"key":"ip","message":"ip is required."}]} Missing or incorrect keys/values. Returns a list with a message per key error. - - -## delete host - -**DELETE** /`api/hosts/` +Get information about the currently authenticated user. ```bash -curl -H "Content-Type: application/json" -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" -X DELETE https://proxy-host.com/api/hosts +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/user/me ``` -* 200 {"message":"Host yours.com deleted"} -* 404 {"name": "HostNotFound", "message": "Host does not exists"} +**Responses:** +- `200` `{"username": "myuser"}` +### Create User -## create invite token +**POST** `/api/user` -**post** `/users/invite` +Create a new user. ```bash -curl -H "Content-Type: application/json" -H "auth-token: 0b06eb2e-4ca4-4881-9a0f-b8df55431cd1" -X POST https://proxy-host.com/users/invite +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"username": "newuser", "password": "newpassword"}' \ + https://proxy-host.com/api/user ``` -* 200 {"token":"5caf94d2-2c91-4010-8df7-968d10802b9d"} +**Responses:** +- `200` User created successfully +- `409` Username already exists +- `422` `{"name": "ObjectValidateError", "message": ...}` Validation error +### Delete User -## sing up +**DELETE** `/api/user/:username` -**post** `/auth/invite/` +Delete a user account. ```bash -curl -H "Content-Type: application/json" -X POST -d "{\"username\": \"test9\", \"password\": \"palm7\"}" https://proxy-host.com/auth/invite/b33d8819-ec64-4cf4-a6ec-77562d738fa4 - +curl -H "auth-token: your-token-here" \ + -X DELETE \ + https://proxy-host.com/api/user/olduser ``` -* 200 {"user":"test9","token":"af662d8b-3d44-4110-8ad9-047dc752d97f"} -* 400 {"message":"Missing fields"} -* 401 {"message":"Token not valid"} -* 409 {"message":"username taken"} +**Responses:** +- `200` `{"username": "olduser", "results": ...}` +- `404` User not found +### Change Password (Self) -## login +**PUT** `/api/user/password` -**post** `/auth/login` +Change the password for the currently authenticated user. ```bash -curl -H "Content-Type: application/json" -X POST -d '{"username": "test8", "password": "mypassword"}' https://proxy-host.com/auth/login +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X PUT \ + -d '{"password": "newpassword"}' \ + https://proxy-host.com/api/user/password ``` -* 200 {"login":true,"token":"027d3964-7d81-4462-a6f9-2c1f9b40b4be"} -* 401 {"login":false} +**Responses:** +- `200` `{"results": ...}` Password changed successfully +### Change Password (Other User) -## verify SSH key +**PUT** `/api/user/password/:username` -**post** `/auth/verifykey` +Change the password for another user (admin function). ```bash -curl -H "Content-Type: application/json" -X POST -d "{\"key\":\"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDM9vboz5YGgESsrR2e4JOeP2qtmQo2S8BjI+Y/VxPQ6WbNFzAkXxDniHcnPCrhkeX36SKINvMjWnt4XOK2S+X+1tCoXJzqtcKKyK0gx8ijBxcWVPxsMWjMYTGSVSKiKnt6CyQzrbVGJMh3iAQ8Yv1JwH+6SAtMgT8it7iLyntNFJCesh4I/znEG58A5VBbdUle1Ztz9afjj1CZns17jk7KPm9ig5DmuvdvnMEfhFjfKv1Rp6S5nxacMoTP4tJNSEUh55IicoWk94ii5GwUVLYgyMmzdlA32TqVLFpU2yAvdA9WSnBaI/ZyktlfI7YAmK2wFBsagr9Pq1TcUAY6rZ/GTMjDxExgdYn/FxlufcuqeNJsJXs2A+0xDS/9mv/yGQzNZrL8DrVhY2OKKLoH4Q7enDbhSgEFmJUJMqPxuPEgLEvKfzcURSvIwRj1iCEw6S4dhdaLJl2RRBb1ZWBQbE5ogIbvAl7GFJUAhj3pqYJnd30VENv1MkK+IoCS7EEP0caqL9RNAId0Plud7q2XElHqzkYUE+z+Q/LvGgclXK1ZmZejNaMnV53wfhAevfwVyNGK9i5gbwc1P2lplIa5laXCcVWezqELEkTpdjp4AeKmMuCr8rY8EnLKIcKWEOsX5UumztCow6e1E55v3VeHvRZLpw4DZP7EE0Q8B/jPFWqbCw== wmantly@gmail.com\"}" https://proxy-host.com/auth/verifykey +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X PUT \ + -d '{"password": "newpassword"}' \ + https://proxy-host.com/api/user/password/otheruser ``` -* 200 {"info":"4096 SHA256:dfdCYzt0atMBXVZTJzUxsu99IjXXFXpocSox5q+jOs8 wmantly@gmail.com (RSA)\n"} -* 400 {"message":"Key is not a public key file!"} +**Responses:** +- `200` `{"results": ...}` Password changed successfully +- `404` User not found +### Create Invite Token -## add ssh key to current user +**POST** `/api/user/invite` -**post** `/users/key` +Create an invitation token for new user registration. ```bash -curl -H "Content-Type: application/json" -H "auth-token: 8eff4f16-086d-40fd-acbd-7634b9a36117" -X POST -d "{\"key\": \"ssh-rsa AAAAB3NzaC1yc2EAAjWnt4XOK2S+X+1tCoXJzqtcKKyK0gx8ijBxcWVPxsMWjMYTGSVSKiKnt6CyQzrbVGJMh3iAQ8Yv1JwH+6SAtMgT8it7iLyntNFJCesh4I/znEG58A5VBbdUle1Ztz9afjj1CZns17jk7KPm9ig5DmuvdvnMEfhFjfKv1Rp6S5nxacMoTP4tJNSEUh55IicoWk94ii5GwUVLYgyMmzdlA32TqVLFpU2yAvdA9WSnBaI/ZyktlfI7YAmK2wFBsagr9Pq1TcUAY6rZ/GTMjDxExgdYn/FxlufcuqeNJsJXs2A+0xDS/9mv/yGQzNZrL8DrVhY2OKKLoH4Q7enDbhSgEFmJUJMqPxuPEgLEvKfzcURSvIwRj1iCEw6S4dhdaLJl2RRBb1ZWBQbE5ogIbvAl7GFJUAhj3pqYJnd30VENv1MkK+IoCS7EEP0caqL9RNAId0Plud7q2XElHqzkYUE+z+Q/LvGgclXK1ZmZejNaMnV53wfhAevfwVyNGK9i5gbwc1P2lplIa5laXCcVWezqELEkTpdjp4AeKmMuCr8rY8EnLKIcKWEOsX5UumztCow6e1E55v3VeHvRZLpw4DZP7EE0Q8B/jPFWqbCw== wmantly@gmail.co\"}" https://proxy-host.com/users/key +curl -H "auth-token: your-token-here" \ + -X POST \ + https://proxy-host.com/api/user/invite ``` -* 200 {"message":true} -* 400 {"message":"Bad SSH key"} +**Responses:** +- `200` `{"token": "5caf94d2-2c91-4010-8df7-968d10802b9d"}` + +### Add SSH Key + +**POST** `/api/user/key` + +Add an SSH public key to the current user's account. + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"key": "ssh-rsa AAAAB3..."}' \ + https://proxy-host.com/api/user/key +``` + +**Responses:** +- `200` `{"message": true}` Key added successfully +- `400` `{"message": "Bad SSH key"}` Invalid key format + +--- + +## Hosts + +Manage proxy host configurations. + +### List Hosts + +**GET** `/api/host` + +Get list of all configured hosts. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/host +``` + +**Query Parameters:** +- `detail` - Include full host details (optional) + +**Responses:** +- `200` `{"results": ["example.com", "*.wildcard.com"]}` +- `200` `{"results": [{"host": "example.com", "ip": "192.168.1.10", ...}, ...]}` (with `?detail=true`) + +### Get Host + +**GET** `/api/host/:host` + +Get configuration for a specific host. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/host/example.com +``` + +**Responses:** +- `200` `{"item": "example.com", "results": {"host": "example.com", "ip": "192.168.1.10", "targetPort": 8080, ...}}` +- `404` `{"name": "HostNotFound", "message": "Host does not exists"}` + +### Lookup Host + +**GET** `/api/host/lookup/:domain` + +Test the host lookup algorithm (supports wildcard matching). + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/host/lookup/sub.example.com +``` + +**Responses:** +- `200` `{"string": "sub.example.com", "results": {"host": "*.example.com", ...}}` +- `200` `{"string": "sub.example.com", "results": null}` (no match) + +### Get Lookup Tree + +**GET** `/api/host/lookupobj` + +Get the internal lookup tree structure (for debugging). + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/host/lookupobj +``` + +**Responses:** +- `200` `{"results": {"com": {"example": {...}}}}` + +### Create Host + +**POST** `/api/host` + +Add a new host configuration. + +**Parameters:** +- `host` (required) - Domain name (e.g., `example.com`, `*.example.com`) +- `ip` (required) - Target IP address or FQDN +- `targetPort` (required) - Target port number (1-65535) +- `forcessl` (optional) - Force HTTPS redirect (default: true) +- `targetssl` (optional) - Use HTTPS to backend (default: false) +- `challengeType` (optional) - For wildcards: `DNS-01-wildcard` or `wildcardChild` + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"host": "example.com", "ip": "192.168.1.10", "targetPort": 8080, "forcessl": true, "targetssl": false}' \ + https://proxy-host.com/api/host +``` + +**Responses:** +- `200` `{"message": "\"example.com\" added.", "host": "example.com", ...}` +- `409` `{"name": "HostNameUsed", "message": "Host already exists"}` +- `422` `{"name": "ObjectValidateError", "message": ...}` Validation error + +### Update Host + +**PUT** `/api/host/:host` + +Update an existing host configuration. + +**Parameters:** Same as Create Host (all optional) + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X PUT \ + -d '{"ip": "192.168.1.20", "targetPort": 9000}' \ + https://proxy-host.com/api/host/example.com +``` + +**Responses:** +- `200` `{"message": "\"example.com\" updated.", ...}` +- `404` `{"name": "HostNotFound", "message": "Host does not exists"}` +- `422` Validation error + +### Delete Host + +**DELETE** `/api/host/:host` + +Remove a host configuration. + +```bash +curl -H "auth-token: your-token-here" \ + -X DELETE \ + https://proxy-host.com/api/host/example.com +``` + +**Responses:** +- `200` `{"message": "example.com deleted", ...}` +- `404` `{"name": "HostNotFound", "message": "Host does not exists"}` + +### Renew Wildcard Certificate + +**PUT** `/api/host/:host/renew` + +Manually trigger wildcard certificate renewal. + +```bash +curl -H "auth-token: your-token-here" \ + -X PUT \ + https://proxy-host.com/api/host/*.example.com/renew +``` + +**Responses:** +- `200` `{"message": "Requesting wildcard cert for *.example.com"}` +- `404` Host not found + +--- + +## DNS Providers + +Manage DNS provider integrations for wildcard SSL certificates. + +### List DNS Providers + +**GET** `/api/dns` + +Get list of configured DNS providers. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/dns +``` + +**Query Parameters:** +- `detail` - Include full provider details (optional) + +**Responses:** +- `200` `{"results": ["provider-id-1", "provider-id-2"]}` + +### List Available Provider Types + +**OPTIONS** `/api/dns` + +Get list of supported DNS provider types and their configuration requirements. + +```bash +curl -H "auth-token: your-token-here" \ + -X OPTIONS \ + https://proxy-host.com/api/dns +``` + +**Responses:** +- `200` `{"results": [{"name": "CloudFlare", "fields": {...}}, {"name": "DigitalOcean", ...}, ...]}` + +### Create DNS Provider + +**POST** `/api/dns` + +Configure a new DNS provider. + +**CloudFlare:** +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"name": "My CloudFlare", "dnsProvider": "Cloudflare", "token": "your-api-token"}' \ + https://proxy-host.com/api/dns +``` + +**DigitalOcean:** +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"name": "My DO", "dnsProvider": "DigitalOcean", "token": "your-api-token"}' \ + https://proxy-host.com/api/dns +``` + +**PorkBun:** +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X POST \ + -d '{"name": "My PorkBun", "dnsProvider": "PorkBun", "apiKey": "pk_xxx", "secretApiKey": "sk_xxx"}' \ + https://proxy-host.com/api/dns +``` + +**Responses:** +- `200` `{"message": "\"provider-id\" added.", ...}` +- `422` Validation error or invalid API credentials + +### Get DNS Provider + +**GET** `/api/dns/:id` + +Get a specific DNS provider configuration. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/dns/provider-id +``` + +**Responses:** +- `200` `{"item": "provider-id", "results": {...}}` +- `404` Provider not found + +### Update DNS Provider + +**PUT** `/api/dns/:id` + +Update DNS provider configuration. + +```bash +curl -H "Content-Type: application/json" \ + -H "auth-token: your-token-here" \ + -X PUT \ + -d '{"name": "Updated Name"}' \ + https://proxy-host.com/api/dns/provider-id +``` + +**Responses:** +- `200` `{"message": "\"provider-id\" updated.", ...}` +- `404` Provider not found + +### Delete DNS Provider + +**DELETE** `/api/dns/:id` + +Remove a DNS provider and all associated domains. + +```bash +curl -H "auth-token: your-token-here" \ + -X DELETE \ + https://proxy-host.com/api/dns/provider-id +``` + +**Responses:** +- `200` `{"message": "provider-id deleted", ...}` +- `404` Provider not found + +### List Domains + +**GET** `/api/dns/domain` + +List all domains from all configured providers. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/dns/domain +``` + +**Query Parameters:** +- `detail` - Include full domain details (optional) + +**Responses:** +- `200` `{"results": ["example.com", "test.com"]}` + +### Get Domain + +**GET** `/api/dns/domain/:domain` + +Get details for a specific domain. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/dns/domain/example.com +``` + +**Responses:** +- `200` `{"results": [{"domain": "example.com", "zoneId": "...", ...}]}` +- `404` Domain not found + +### Refresh Domains + +**POST** `/api/dns/domain/refresh/:providerId` + +Refresh the domain list from a DNS provider's API. + +```bash +curl -H "auth-token: your-token-here" \ + -X POST \ + https://proxy-host.com/api/dns/domain/refresh/provider-id +``` + +**Responses:** +- `200` `{"results": ...}` Updated domain list +- `404` Provider not found + +--- + +## Certificates + +Retrieve SSL certificate information. + +### Get Certificate + +**GET** `/api/cert/:host` + +Get the SSL certificate for a host. + +```bash +curl -H "auth-token: your-token-here" \ + https://proxy-host.com/api/cert/example.com +``` + +**Responses:** +- `200` Certificate data including `cert_pem`, `fullchain_pem`, `privkey_pem`, expiry information +- `404` Certificate not found + +--- + +## Error Responses + +All endpoints may return the following error responses: + +- `401` `{"name": "LoginFailed", "message": "Invalid Credentials, login failed."}` - Authentication required or invalid +- `404` `{"name": "NotFound", "message": "..."}` - Resource not found +- `422` `{"name": "ObjectValidateError", "message": [...], "keys": [...]}` - Validation errors +- `500` Internal server error + +## Notes + +- All timestamps are in milliseconds since epoch +- The `auth-token` header is required for all authenticated endpoints +- Host names support wildcards: `*` (single level) and `**` (multi-level) +- DNS providers are validated on creation - invalid API credentials will be rejected +- Wildcard certificates are automatically renewed 30 days before expiration diff --git a/nodejs/app.js b/nodejs/app.js index 769dfd9..b64b5d4 100755 --- a/nodejs/app.js +++ b/nodejs/app.js @@ -19,6 +19,15 @@ const middleware = require('./middleware/auth'); // Grab the projects PubSub app.contoller = require('./controller'); +/** + * Start background services + * These services run independently of the HTTP server: + * - host_lookup: Unix socket server for OpenResty host lookups + * - host_scheduler: Scheduled tasks for wildcard cert renewal + */ +require('./services/host_lookup'); +require('./services/host_scheduler'); + // Push pubsub over the socket and back. app.onListen.push(function(){ app.io.use(middleware.authIO); diff --git a/nodejs/controller/auth.js b/nodejs/controller/auth.js deleted file mode 100644 index d117173..0000000 --- a/nodejs/controller/auth.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -const Table = require('../models'); -const {User, AuthToken} = Table.models; - - -class Auth{ - static errors = { - login: function(){ - let error = new Error('LoginFailed'); - error.name = 'LoginFailed'; - error.message = `Invalid Credentials, login failed.`; - error.status = 401; - - return error; - } - } - - static async login(data){ - try{ - let user = await User.login(data); - let token = await AuthToken.create({username: user.username}); - - return {user, token} - }catch(error){ - console.log('login error', error); - throw this.errors.login(); - } - } - - static async checkToken(token){ - try{ - token = await AuthToken.get(token); - if(token && token.check()) return token; - - throw this.errors.login(); - }catch(error){ - console.log('check error', error); - throw this.errors.login(); - } - } - - static async logout(data){ - let token = await AuthToken.get(data); - await token.destroy(); - } -} - -module.exports = {Auth}; diff --git a/nodejs/controller/host.js b/nodejs/controller/host.js deleted file mode 100644 index ff5a591..0000000 --- a/nodejs/controller/host.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -const {Host} = require('../models/host'); -const {SocketServerJson} = require('../models/socket_server_json'); -const conf = require('../conf'); - - -const socket = new SocketServerJson({ - socketFile: conf.socketFile, - onData: function(data, clientSocket) { - try{ - console.log('socket lookup', data) - let parentHost = Host.lookUp(data['domain']); - console.log('socket found host', parentHost); - if(!parentHost) return clientSocket.write(JSON.stringify({})); - if(!parentHost.wildcard_parent){ - parentHost.wildcard_parent = parentHost.host; - Host.addCache(data['domain'], parentHost); - } - - for(const [key, value] of Object.entries(parentHost)) { - parentHost[key] = String(value); - }; - - clientSocket.write(JSON.stringify(parentHost)); - }catch(error){ - console.error('controler/hosts onData error', error) - } - }, - onListen: function(){ - console.log('Unix socket listening on', conf.socketFile) - } -}); diff --git a/nodejs/controller/index.js b/nodejs/controller/index.js index 32084e9..c84dbbf 100644 --- a/nodejs/controller/index.js +++ b/nodejs/controller/index.js @@ -1,8 +1,6 @@ 'use strict'; module.exports = { - auth: require('./auth'), ps: require('./pubsub'), - host: require('./host'), } diff --git a/nodejs/hostcontrol.js b/nodejs/hostcontrol.js deleted file mode 100755 index 8389943..0000000 --- a/nodejs/hostcontrol.js +++ /dev/null @@ -1,25 +0,0 @@ -#! /usr/bin/env node - -//you must add the absolute path to hosts.js on line 4, or this file will NOT work -const hosts = require("./models/hosts.js") - -const command = process.argv[2]; - -(async function(command){ - if (command == "--list"){ - console.log(await hosts.listAll()) - process.exit(0) - } - -})(command) -/* - if process.argv[2] == "--info" - - if process.agrv[2] == "--add" - - if process.argv[2] == "--remove" - - else{ - console.log("help text") - } -*/ \ No newline at end of file diff --git a/nodejs/middleware/auth.js b/nodejs/middleware/auth.js index 802d7d1..7918d9a 100755 --- a/nodejs/middleware/auth.js +++ b/nodejs/middleware/auth.js @@ -1,6 +1,6 @@ 'use strict'; -const {Auth} = require('../controller/auth'); +const {Auth} = require('../models/auth'); async function auth(req, res, next){ try{ diff --git a/nodejs/models/auth.js b/nodejs/models/auth.js new file mode 100644 index 0000000..b7bb581 --- /dev/null +++ b/nodejs/models/auth.js @@ -0,0 +1,96 @@ +'use strict'; + +const Table = require('../models'); +const {User, AuthToken} = Table.models; + +/** + * Auth Model + * + * Handles authentication operations for the application. + * Manages user login, token validation, and logout processes. + * + * Dependencies: + * - User model: Validates user credentials + * - AuthToken model: Creates and manages authentication tokens + * + * All methods throw standardized login errors on failure to avoid + * leaking information about whether usernames exist or tokens are valid. + */ +class Auth{ + /** + * Standardized error responses for authentication failures. + * Returns generic "Invalid Credentials" message for security. + */ + static errors = { + login: function(){ + let error = new Error('LoginFailed'); + error.name = 'LoginFailed'; + error.message = `Invalid Credentials, login failed.`; + error.status = 401; + + return error; + } + } + + /** + * Authenticate user and create session token. + * + * @param {Object} data - Login credentials {username, password} + * @returns {Object} {user, token} - User object and auth token + * @throws {Error} Generic login error on any failure + * + * Flow: + * 1. Validate credentials via User.login() + * 2. Create new AuthToken for the user + * 3. Return both user data and token + */ + static async login(data){ + try{ + let user = await User.login(data); + let token = await AuthToken.create({username: user.username}); + + return {user, token} + }catch(error){ + console.log('login error', error); + throw this.errors.login(); + } + } + + /** + * Validate an authentication token. + * + * @param {string} token - Token string to validate + * @returns {Object} Token object if valid + * @throws {Error} Generic login error if token invalid or expired + * + * Checks: + * 1. Token exists in database + * 2. Token has not expired (via token.check()) + */ + static async checkToken(token){ + try{ + token = await AuthToken.get(token); + if(token && token.check()) return token; + + throw this.errors.login(); + }catch(error){ + console.log('check error', error); + throw this.errors.login(); + } + } + + /** + * Destroy an authentication token (logout). + * + * @param {string} data - Token string to destroy + * @returns {void} + * + * Removes token from database, invalidating the session. + */ + static async logout(data){ + let token = await AuthToken.get(data); + await token.destroy(); + } +} + +module.exports = {Auth}; diff --git a/nodejs/models/host.js b/nodejs/models/host.js index ca04014..4783895 100755 --- a/nodejs/models/host.js +++ b/nodejs/models/host.js @@ -39,17 +39,12 @@ class Host extends Table{ static async addCache(host, parentOBJ){ try{ - console.log('addCache host:', host, 'parentOBJ host', parentOBJ.host) parentOBJ = await this.get(parentOBJ.host); if(parentOBJ.is_cache){ - console.log('addCache parentOBJ is chace, skipping') return; } - console.log('addCache, corrent parent?', parentOBJ.wildcard_parent || parentOBJ.host) - console.log('addCache, got parent', parentOBJ) - await this.create({ ...parentOBJ, host: host, @@ -63,7 +58,7 @@ class Host extends Table{ parent: parentOBJ.host }); }catch(error){ - console.error('add cache error', {...parentOBJ, host, is_cache: true}, error) + console.error('add cache error', {...parentOBJ, host, is_cache: true}, error); throw error; } } @@ -81,18 +76,35 @@ class Host extends Table{ }catch(error){ console.error('bust cache error', error) - throw error; } } static async create(data, ...args){ try{ - if(data.is_wildcard) await this.validateWildcardCreate(data, args); + // Validate requested host is valid host and domain + if(data.challengeType === 'DNS-01-wildcard') await this.validateWildcardCreate(data, args); + // Validate requested host has a valid wildcard parent + if(data.challengeType === 'wildcardChild'){ + let parentHost = await this.lookUp(data.host); + console.log('parentHost:', parentHost) + if(parentHost.is_wildcard){ + data.wildcard_parent = parentHost.host; + }else{ + throw new Error(`No parent wild card for ${data.host}`); + } + } + + // Create the new host entry let out = await super.create(data, ...args); + + // Update the lookup table to reflect new host await this.buildLookUpObj(); - if(out.is_wildcard) out.createWildcardCert(); + + // Fire the request for the wild card cert + // This is "back ground" job, await is intentionally missing + if(out.challengeType === 'DNS-01-wildcard') out.createWildcardCert(); return out; @@ -134,7 +146,8 @@ class Host extends Table{ type:'TXT', name: `_acme-challenge${parts.sub ? `.${parts.sub}` : ''}`, data: `${keyAuthorization}` - } + }, + true // Force the record creation, even if the record exists ); }catch(error){ console.log('model Host challengeCreateFn error:', error) @@ -215,6 +228,26 @@ class Host extends Table{ } } + async checkWildcardForRenew(){ + try{ + if(this.is_wildcard && Date.now() > this.wildcard_expires - (30 * 24 * 60 * 60 * 1000)){ + this.createWildcardCert(); + } + }catch(error){ + throw error; + } + } + + static async checkWildcardForRenew(){ + try{ + for(let host of await this.listDetail()){ + host.createWildcardCert(); + } + }catch(error){ + throw error; + } + } + async update(...args){ try{ let out = await super.update(...args) @@ -330,6 +363,7 @@ class Host extends Table{ // Check every 5ms to see if the look up tree is ready while(!this.__lookUpIsReady) await new Promise(r => setTimeout(r, 5)); + return true; } } diff --git a/nodejs/models/socket_server_json.js b/nodejs/models/socket_server_json.js deleted file mode 100644 index f34d850..0000000 --- a/nodejs/models/socket_server_json.js +++ /dev/null @@ -1,88 +0,0 @@ -'use strict'; - -const net = require('net'); -const fs = require('fs'); -const {CallbackQueue} = require('../utils/callback_queue') - -class SocketServerJson { - constructor(args){ - this.socketFile = args.socketFile; - this.onData = new CallbackQueue(args.onData, this); - this.onListen = new CallbackQueue(args.onListen, this); - this.onError = new CallbackQueue(args.onError); - this.onCLientNew = new CallbackQueue(args.onCLientNew); - this.onCLientClose = new CallbackQueue(args.onCLientClose); - this.onCLientError = new CallbackQueue(args.onCLientClose); - - this.onListen.push(function(){ - fs.chmodSync(args.socketFile, '777'); - }) - - this.listen(); - - } - - __resetSocketFile(callback){ - let instance = this; - - fs.stat(this.socketFile, function (err, stats) { - if (stats) { - fs.unlink(instance.socketFile, function(err){ - if(err){ - // This should never happen. - console.error(err); - } - callback(...arguments) - }); - }else{ - callback() - } - - }); - } - - - __setUpServer(){ - - let instance = this; - this.socket = net.createServer(); - - this.socket.on('connection', function(clientSocket){ - let buffer = ''; - - clientSocket.on('data', function(data){ - buffer += data.toString(); - try{ - instance.onData.call(JSON.parse(data), clientSocket) - buffer = '' - // clientSocket.write(JSON.stringify(Host.lookUp(buffer)|| {host: 'none'})); - - }catch(error){ - ; - } - }); - - clientSocket.on('close', instance.onCLientClose.call.bind(instance.onCLientClose)); - - clientSocket.on('error', instance.onCLientError.call.bind(instance.onCLientError)); - - }); - - this.socket.on('error', this.onError.call.bind(this.onError)) - - this.socket.on('listening', this.onListen.call.bind(this.onListen)); - } - - listen(){ - let instance = this; - - this.__setUpServer(); - - this.__resetSocketFile(function(){ - instance.socket.listen(instance.socketFile); - }); - - } -}; - -module.exports = {SocketServerJson}; diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 11994e0..56ce34a 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -18,6 +18,7 @@ "ejs": "^3.1.10", "express": "^4.19.2", "extend": "^3.0.2", + "jq-repeat": "^2.0.0", "jquery": "^3.7.1", "ldapts": "^2.12.0", "linux-sys-user": "^1.1.8", @@ -33,9 +34,10 @@ } }, "node_modules/@fortawesome/fontawesome-free": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.6.0.tgz", - "integrity": "sha512-60G28ke/sXdtS9KZCpZSHHkCbdsOGEhIUGlwq6yhY74UpTiToIh8np7A8yphhM4BWsvNFtIvLpi4co+h9Mr9Ow==", + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.7.2.tgz", + "integrity": "sha512-JUOtgFW6k9u4Y+xeIaEiLr3+cjoUPiAuLXoyKOJSia6Duzb7pq+A76P9ZdPDoAoxHdHzq6gE9/jKBGXlZT8FbA==", + "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)", "engines": { "node": ">=6" } @@ -44,6 +46,7 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", "dependencies": { "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", @@ -60,144 +63,158 @@ } }, "node_modules/@peculiar/asn1-cms": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.3.8.tgz", - "integrity": "sha512-Wtk9R7yQxGaIaawHorWKP2OOOm/RZzamOmSWwaqGphIuU6TcKYih0slL6asZlSSZtVoYTrBfrddSOD/jTu9vuQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.0.tgz", + "integrity": "sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "@peculiar/asn1-x509-attr": "^2.3.8", - "asn1js": "^3.0.5", - "tslib": "^2.6.2" + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "@peculiar/asn1-x509-attr": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-csr": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.3.8.tgz", - "integrity": "sha512-ZmAaP2hfzgIGdMLcot8gHTykzoI+X/S53x1xoGbTmratETIaAbSWMiPGvZmXRA0SNEIydpMkzYtq4fQBxN1u1w==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.0.tgz", + "integrity": "sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "asn1js": "^3.0.5", - "tslib": "^2.6.2" + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-ecc": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.3.8.tgz", - "integrity": "sha512-Ah/Q15y3A/CtxbPibiLM/LKcMbnLTdUdLHUgdpB5f60sSvGkXzxJCu5ezGTFHogZXWNX3KSmYqilCrfdmBc6pQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.0.tgz", + "integrity": "sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "asn1js": "^3.0.5", - "tslib": "^2.6.2" + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pfx": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.3.8.tgz", - "integrity": "sha512-XhdnCVznMmSmgy68B9pVxiZ1XkKoE1BjO4Hv+eUGiY1pM14msLsFZ3N7K46SoITIVZLq92kKkXpGiTfRjlNLyg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.0.tgz", + "integrity": "sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.3.8", - "@peculiar/asn1-pkcs8": "^2.3.8", - "@peculiar/asn1-rsa": "^2.3.8", - "@peculiar/asn1-schema": "^2.3.8", - "asn1js": "^3.0.5", - "tslib": "^2.6.2" + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-pkcs8": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.3.8.tgz", - "integrity": "sha512-rL8k2x59v8lZiwLRqdMMmOJ30GHt6yuHISFIuuWivWjAJjnxzZBVzMTQ72sknX5MeTSSvGwPmEFk2/N8+UztFQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.0.tgz", + "integrity": "sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "asn1js": "^3.0.5", - "tslib": "^2.6.2" + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.3.8.tgz", - "integrity": "sha512-+nONq5tcK7vm3qdY7ZKoSQGQjhJYMJbwJGbXLFOhmqsFIxEWyQPHyV99+wshOjpOjg0wUSSkEEzX2hx5P6EKeQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.0.tgz", + "integrity": "sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.3.8", - "@peculiar/asn1-pfx": "^2.3.8", - "@peculiar/asn1-pkcs8": "^2.3.8", - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "@peculiar/asn1-x509-attr": "^2.3.8", - "asn1js": "^3.0.5", - "tslib": "^2.6.2" + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-pfx": "^2.6.0", + "@peculiar/asn1-pkcs8": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "@peculiar/asn1-x509-attr": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-rsa": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.3.8.tgz", - "integrity": "sha512-ES/RVEHu8VMYXgrg3gjb1m/XG0KJWnV4qyZZ7mAg7rrF3VTmRbLxO8mk+uy0Hme7geSMebp+Wvi2U6RLLEs12Q==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.0.tgz", + "integrity": "sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "asn1js": "^3.0.5", - "tslib": "^2.6.2" + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-schema": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", - "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", + "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", + "license": "MIT", "dependencies": { - "asn1js": "^3.0.5", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2" + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-x509": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.3.8.tgz", - "integrity": "sha512-voKxGfDU1c6r9mKiN5ZUsZWh3Dy1BABvTM3cimf0tztNwyMJPhiXY94eRTgsMQe6ViLfT6EoXxkWVzcm3mFAFw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.0.tgz", + "integrity": "sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "asn1js": "^3.0.5", - "ipaddr.js": "^2.1.0", - "pvtsutils": "^1.3.5", - "tslib": "^2.6.2" + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.3.8.tgz", - "integrity": "sha512-4Z8mSN95MOuX04Aku9BUyMdsMKtVQUqWnr627IheiWnwFoheUhX3R4Y2zh23M7m80r4/WG8MOAckRKc77IRv6g==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.0.tgz", + "integrity": "sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "asn1js": "^3.0.5", - "tslib": "^2.6.2" + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/x509": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.11.0.tgz", - "integrity": "sha512-8rdxE//tsWLb2Yo2TYO2P8gieStbrHK/huFMV5PPfwX8I5HmtOus+Ox6nTKrPA9o+WOPaa5xKenee+QdmHBd5g==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.2.tgz", + "integrity": "sha512-r2w1Hg6pODDs0zfAKHkSS5HLkOLSeburtcgwvlLLWWCixw+MmW3U6kD5ddyvc2Y2YdbGuVwCF2S2ASoU1cFAag==", + "license": "MIT", "dependencies": { - "@peculiar/asn1-cms": "^2.3.8", - "@peculiar/asn1-csr": "^2.3.8", - "@peculiar/asn1-ecc": "^2.3.8", - "@peculiar/asn1-pkcs9": "^2.3.8", - "@peculiar/asn1-rsa": "^2.3.8", - "@peculiar/asn1-schema": "^2.3.8", - "@peculiar/asn1-x509": "^2.3.8", - "pvtsutils": "^1.3.5", + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", "reflect-metadata": "^0.2.2", - "tslib": "^2.6.2", - "tsyringe": "^4.8.0" + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" + }, + "engines": { + "node": ">=22.0.0" } }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -207,14 +224,16 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/client": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.0.tgz", - "integrity": "sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.6.1.tgz", + "integrity": "sha512-/KCsg3xSlR+nCK8/8ZYSknYxvXHwubJrU82F3Lm1Fp6789VQ0/3RJKfsmRXjqfaTA++23CvC3hqmqe/2GEt6Kw==", + "license": "MIT", "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -228,6 +247,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -236,6 +256,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.7.tgz", "integrity": "sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -244,6 +265,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.2.0.tgz", "integrity": "sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -252,6 +274,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.1.0.tgz", "integrity": "sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -259,25 +282,23 @@ "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" }, "node_modules/@types/asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/@types/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-V91DSJ2l0h0gRhVP4oBfBzRBN9lAbPUkGDMCnwedqPKX2d84aAMc9CulOvxdw1f7DfEYx99afab+Rsm3e52jhA==", + "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" - }, "node_modules/@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -285,22 +306,26 @@ "node_modules/@types/node": { "version": "14.14.45", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.45.tgz", - "integrity": "sha512-DssMqTV9UnnoxDWu959sDLZzfvqCF0qDNRjaWeYSui9xkFe61kKo4l1TWNTQONpuXEm+gLMRvdlzvNHBamzmEw==" + "integrity": "sha512-DssMqTV9UnnoxDWu959sDLZzfvqCF0qDNRjaWeYSui9xkFe61kKo4l1TWNTQONpuXEm+gLMRvdlzvNHBamzmEw==", + "license": "MIT" }, "node_modules/@types/uuid": { "version": "8.3.4", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT" }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC" }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -313,6 +338,7 @@ "version": "5.4.0", "resolved": "https://registry.npmjs.org/acme-client/-/acme-client-5.4.0.tgz", "integrity": "sha512-mORqg60S8iML6XSmVjqjGHJkINrCGLMj2QvDmFzI9vIlv1RGlyjmw3nrzaINJjkNsYXC41XhhD5pfy7CtuGcbA==", + "license": "MIT", "dependencies": { "@peculiar/x509": "^1.11.0", "asn1js": "^3.0.5", @@ -328,6 +354,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", "dependencies": { "debug": "4" }, @@ -339,29 +366,17 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -371,15 +386,17 @@ } }, "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC" }, "node_modules/are-we-there-yet": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -391,58 +408,66 @@ "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } }, "node_modules/asn1js": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", - "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "license": "BSD-3-Clause", "dependencies": { - "pvtsutils": "^1.3.2", + "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", - "tslib": "^2.4.0" + "tslib": "^2.8.1" }, "engines": { "node": ">=12.0.0" } }, "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/axios": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", - "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", "engines": { "node": "^4.5.0 || >= 5.9" } @@ -452,6 +477,7 @@ "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", "integrity": "sha512-AGBHOG5hPYZ5Xl9KXzU5iKq9516yEmvCKDg3ecP5kX2aB6UqTeXZxk2ELnDgDm6BQSMlLt9rDB4LoSMx0rYwww==", "hasInstallScript": true, + "license": "MIT", "dependencies": { "@mapbox/node-pre-gyp": "^1.0.11", "node-addon-api": "^5.0.0" @@ -465,6 +491,7 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -473,22 +500,23 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "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.11.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -499,6 +527,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -506,12 +535,13 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/bootstrap": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", - "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz", + "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==", "funding": [ { "type": "github", @@ -522,17 +552,18 @@ "url": "https://opencollective.com/bootstrap" } ], + "license": "MIT", "peerDependencies": { "@popperjs/core": "^2.11.8" } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -540,6 +571,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -551,20 +583,32 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "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" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -573,26 +617,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -616,6 +646,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", "engines": { "node": ">=10" } @@ -624,30 +655,16 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", "engines": { "node": ">=0.10.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", "bin": { "color-support": "bin.js" } @@ -656,6 +673,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -666,17 +684,20 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC" }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -688,27 +709,31 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -718,11 +743,12 @@ } }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -733,26 +759,11 @@ } } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -760,12 +771,14 @@ "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT" }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -774,28 +787,46 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", "engines": { "node": ">=8" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/ejs": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "license": "Apache-2.0", "dependencies": { "jake": "^10.8.5" }, @@ -809,31 +840,33 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "version": "6.6.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.5.tgz", + "integrity": "sha512-2RZdgEbXmp5+dVbRm0P7HQUImZpICccJy7rN7Tv+SFa55pH+lxnuw6/K1ZxxBfHoYpSkHLAO92oa8O4SwFXA2A==", + "license": "MIT", "dependencies": { - "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "~0.4.1", + "cookie": "~0.7.2", "cors": "~2.8.5", - "debug": "~4.3.1", + "debug": "~4.4.1", "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" + "ws": "~8.18.3" }, "engines": { "node": ">=10.2.0" @@ -843,25 +876,16 @@ "version": "5.2.3", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", "engines": { "node": ">=10.0.0" } }, - "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -870,6 +894,34 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, "engines": { "node": ">= 0.4" } @@ -877,61 +929,69 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "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.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -939,45 +999,30 @@ "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "license": "Apache-2.0", "dependencies": { "minimatch": "^5.0.1" } }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -986,16 +1031,17 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "statuses": "2.0.1", + "statuses": "~2.0.2", "unpipe": "~1.0.0" }, "engines": { @@ -1006,6 +1052,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -1013,18 +1060,20 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -1035,12 +1084,15 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -1051,6 +1103,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1059,6 +1112,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1067,6 +1121,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -1078,6 +1133,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -1088,7 +1144,8 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -1096,6 +1153,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1108,6 +1166,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1117,6 +1176,7 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.2", @@ -1136,20 +1196,27 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -1158,11 +1225,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1183,6 +1264,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -1190,40 +1272,33 @@ "node": ">= 6" } }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -1231,10 +1306,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -1245,12 +1346,14 @@ "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC" }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -1259,24 +1362,30 @@ } }, "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", "dependencies": { "agent-base": "6", "debug": "4" @@ -1289,6 +1398,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -1300,13 +1410,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1315,14 +1427,16 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", "engines": { - "node": ">= 10" + "node": ">= 0.10" } }, "node_modules/is-binary-path": { @@ -1330,6 +1444,7 @@ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -1342,6 +1457,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1350,6 +1466,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } @@ -1359,6 +1476,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -1371,19 +1489,20 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "license": "Apache-2.0", "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", + "async": "^3.2.6", "filelist": "^1.0.4", - "minimatch": "^3.1.2" + "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" @@ -1392,15 +1511,30 @@ "node": ">=10" } }, + "node_modules/jq-repeat": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jq-repeat/-/jq-repeat-2.0.1.tgz", + "integrity": "sha512-ATI25tKQG3uHW8f8XPqBe85JsH4PNGHA/YLy1KgMVeYDoUSf9cqGNBum+4A+Pg1WKh9PA6bYyWfYNsgktwIbSg==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "jquery": ">=3.0.0", + "mustache": ">=4.0.0" + } + }, "node_modules/jquery": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", - "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "license": "MIT" }, "node_modules/ldapts": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/ldapts/-/ldapts-2.12.0.tgz", "integrity": "sha512-rjx0s1683rLidMghRvf0AX0JM2KJibfF100pOKgBTeAI9ZUFMt2LG4ke2wubi2ITT8A6MB0ZrotjS1uCCE2YcQ==", + "license": "MIT", "dependencies": { "@types/asn1": "~0.2.0", "@types/node": "~14.14.37", @@ -1414,15 +1548,34 @@ "node": ">=10" } }, + "node_modules/ldapts/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/linux-sys-user": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/linux-sys-user/-/linux-sys-user-1.2.0.tgz", - "integrity": "sha512-TyPFnk3kp9kplKPjWtYYbezYzj+Xe47bGu3YZs2Jg3xxLUw/ny0AHL252jpR1c8q32vIQxWK8qLpFZ+qHHC0MQ==" + "integrity": "sha512-TyPFnk3kp9kplKPjWtYYbezYzj+Xe47bGu3YZs2Jg3xxLUw/ny0AHL252jpR1c8q32vIQxWK8qLpFZ+qHHC0MQ==", + "license": "MIT" }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -1437,27 +1590,43 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1466,6 +1635,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -1477,6 +1647,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1485,6 +1656,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -1493,20 +1665,22 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", "engines": { "node": ">=8" } @@ -1515,6 +1689,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -1527,6 +1702,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -1538,6 +1714,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -1549,19 +1726,22 @@ "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", "engines": { "node": "*" } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/mustache": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", "bin": { "mustache": "bin/mustache" } @@ -1570,6 +1750,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1577,12 +1758,14 @@ "node_modules/node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "license": "MIT" }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -1599,18 +1782,20 @@ } }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", + "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", + "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" } }, "node_modules/nodemon": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", - "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz", + "integrity": "sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^3.5.2", "debug": "^4", @@ -1634,31 +1819,35 @@ "url": "https://opencollective.com/nodemon" } }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "node_modules/nodemon/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, - "engines": { - "node": ">=4" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/nodemon/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { - "has-flag": "^3.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=4" + "node": "*" } }, "node_modules/nopt": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", "dependencies": { "abbrev": "1" }, @@ -1674,6 +1863,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1683,6 +1873,7 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "deprecated": "This package is no longer supported.", + "license": "ISC", "dependencies": { "are-we-there-yet": "^2.0.0", "console-control-strings": "^1.1.0", @@ -1694,14 +1885,16 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -1713,6 +1906,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -1724,6 +1918,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -1731,12 +1926,14 @@ "node_modules/p2psub": { "version": "0.1.9", "resolved": "https://registry.npmjs.org/p2psub/-/p2psub-0.1.9.tgz", - "integrity": "sha512-5za6YUq6GLH+iZCqOF7YaOd13joJyqJyjp/6o3wcy9hj969EJq7sJGsU5b3MB7tjMoaHAaIKZ01j99Y9QficUQ==" + "integrity": "sha512-5za6YUq6GLH+iZCqOF7YaOd13joJyqJyjp/6o3wcy9hj969EJq7sJGsU5b3MB7tjMoaHAaIKZ01j99Y9QficUQ==", + "license": "MIT" }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1745,20 +1942,29 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -1770,6 +1976,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -1778,47 +1985,44 @@ "node": ">= 0.10" } }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pvtsutils": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", - "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", "dependencies": { - "tslib": "^2.6.1" + "tslib": "^2.8.1" } }, "node_modules/pvutils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", - "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=16.0.0" } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -1831,19 +2035,21 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -1853,6 +2059,7 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -1867,6 +2074,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -1875,12 +2083,16 @@ } }, "node_modules/redis": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.0.tgz", - "integrity": "sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.7.1.tgz", + "integrity": "sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==", + "license": "MIT", + "workspaces": [ + "./packages/*" + ], "dependencies": { "@redis/bloom": "1.2.0", - "@redis/client": "1.6.0", + "@redis/client": "1.6.1", "@redis/graph": "1.1.1", "@redis/json": "1.0.7", "@redis/search": "1.2.0", @@ -1890,13 +2102,15 @@ "node_modules/reflect-metadata": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -1924,17 +2138,20 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -1943,23 +2160,24 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "range-parser": "~1.2.1", - "statuses": "2.0.1" + "statuses": "~2.0.2" }, "engines": { "node": ">= 0.8.0" @@ -1969,6 +2187,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -1976,22 +2195,19 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "~0.19.1" }, "engines": { "node": ">= 0.8.0" @@ -2000,38 +2216,79 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "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" - }, - "engines": { - "node": ">= 0.4" - } + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -2043,13 +2300,15 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -2058,15 +2317,16 @@ } }, "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", + "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", + "license": "MIT", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", + "debug": "~4.4.1", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, @@ -2075,30 +2335,33 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.6.tgz", + "integrity": "sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==", + "license": "MIT", "dependencies": { - "debug": "~4.3.4", - "ws": "~8.17.1" + "debug": "~4.4.1", + "ws": "~8.18.3" } }, "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.5.tgz", + "integrity": "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" + "debug": "~4.4.1" }, "engines": { "node": ">=10.0.0" } }, "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2106,12 +2369,14 @@ "node_modules/strict-event-emitter-types": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strict-event-emitter-types/-/strict-event-emitter-types-2.0.0.tgz", - "integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==" + "integrity": "sha512-Nk/brWYpD85WlOgzw5h173aci0Teyv8YdIAEtV+N88nDB0dLlazZyJMIsN6eo1/AR61l+p6CJTG1JIyFaoNEEA==", + "license": "ISC" }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -2120,6 +2385,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2133,6 +2399,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2141,20 +2408,23 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/tar": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -2170,13 +2440,15 @@ "node_modules/tld-extract": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/tld-extract/-/tld-extract-2.1.0.tgz", - "integrity": "sha512-Y9QHWIoDQPJJVm3/pOC7kOfOj7vsNSVZl4JGoEHb605FiwZgIfzSMyU0HC0wYw5Cx8435vaG1yGZtIm1yiQGOw==" + "integrity": "sha512-Y9QHWIoDQPJJVm3/pOC7kOfOj7vsNSVZl4JGoEHb605FiwZgIfzSMyU0HC0wYw5Cx8435vaG1yGZtIm1yiQGOw==", + "license": "ISC" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -2188,6 +2460,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } @@ -2197,6 +2470,7 @@ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, + "license": "ISC", "bin": { "nodetouch": "bin/nodetouch.js" } @@ -2204,17 +2478,20 @@ "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, "node_modules/tsyringe": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.8.0.tgz", - "integrity": "sha512-YB1FG+axdxADa3ncEtRnQCFq/M0lALGLxSZeVNbTU8NqhOVc51nnv2CISTcvc1kyv6EGPtXVr0v6lWeDxiijOA==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", + "license": "MIT", "dependencies": { "tslib": "^1.9.3" }, @@ -2225,12 +2502,14 @@ "node_modules/tsyringe/node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -2243,12 +2522,14 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2256,12 +2537,14 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -2270,6 +2553,7 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -2278,6 +2562,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2285,12 +2570,14 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -2300,6 +2587,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -2307,12 +2595,14 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" }, "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -2332,7 +2622,8 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" } } } diff --git a/nodejs/package.json b/nodejs/package.json index 001733c..4ffd538 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -9,7 +9,15 @@ } ], "scripts": { - "start": "node ./bin/www" + "start": "node ./bin/www", + "dev": "npx nodemon --ignore public/ ./bin/www", + "test": "node --test test/unit/callback_queue.test.js test/unit/host_lookup.test.js test/unit/unix_socket.test.js test/integration/dns_provider.test.js", + "test:unit": "node --test test/unit/callback_queue.test.js test/unit/host_lookup.test.js test/unit/unix_socket.test.js", + "test:integration": "node --test test/integration/dns_provider.test.js", + "test:watch": "node --test --watch test/unit/callback_queue.test.js test/unit/host_lookup.test.js test/unit/unix_socket.test.js test/integration/dns_provider.test.js" + }, + "engines": { + "node": ">=18.0.0" }, "dependencies": { "@fortawesome/fontawesome-free": "^6.4.2", @@ -21,6 +29,7 @@ "ejs": "^3.1.10", "express": "^4.19.2", "extend": "^3.0.2", + "jq-repeat": "^2.0.0", "jquery": "^3.7.1", "ldapts": "^2.12.0", "linux-sys-user": "^1.1.8", diff --git a/nodejs/public/css/styles.css b/nodejs/public/css/styles.css index 7db0c02..14a6177 100755 --- a/nodejs/public/css/styles.css +++ b/nodejs/public/css/styles.css @@ -12,3 +12,7 @@ nav.navbar{ font-weight: bold; } +.actionMessage{ + position: fixed; +} + diff --git a/nodejs/public/lib/js/app-base.js b/nodejs/public/lib/js/app-base.js index 486cb0c..517eb07 100644 --- a/nodejs/public/lib/js/app-base.js +++ b/nodejs/public/lib/js/app-base.js @@ -304,31 +304,38 @@ app.util = (function(app){ setTimeout(callback,10) } - $.fn.serializeObject = function(){ - var - arr = $(this).serializeArray(), - obj = {}; + $.fn.serializeObject = function() { + var obj = {}; - for(var i = 0; i < arr.length; i++){ - if(obj[arr[i].name] === undefined) { - if(!arr[i].value) continue; - obj[arr[i].name] = arr[i].value; - let type = $(this).parent().find(`[name="${arr[i].name}"]`).attr('type'); - if(['number', 'range'].includes(type)){ - obj[arr[i].name] = Number(arr[i].value); + // Get the form values and work over them + for (let {name, value} of $(this).serializeArray()) { + console.log(name, value) + if (obj[name] === undefined) { + if (!value + && !$(this).parent().find(`[name="${name}"]`).attr('value') + ){ + continue; } - if(['radio'].includes(type) && ['true', 'false'].includes(arr[i].value)){ - obj[arr[i].name] = arr[i].value == 'true' ? true : false; + obj[name] = value; + + let type = $(this).parent().find(`[name="${name}"]`).attr('type'); + if (['number', 'range'].includes(type)) { + obj[name] = Number(value); + } + + if (['radio'].includes(type) && ['true', 'false'].includes(value)) { + obj[name] = value == 'true' ? true : false; } } else { - if(!(obj[arr[i].name] instanceof Array)) { - obj[arr[i].name] = [obj[arr[i].name]]; + if (!(obj[name] instanceof Array)) { + obj[name] = [obj[name]]; } - obj[arr[i].name].push(arr[i].value); + obj[name].push(value); } } + return obj; }; diff --git a/nodejs/public/lib/js/jq-repeat_new.js b/nodejs/public/lib/js/jq-repeat_new.js deleted file mode 100644 index c4da556..0000000 --- a/nodejs/public/lib/js/jq-repeat_new.js +++ /dev/null @@ -1,394 +0,0 @@ -/* -Author William Mantly Jr -https://github.com/wmantly/jq-repeat -MIT license -*/ - -(function($, Mustache){ -'use strict'; - var scope = {}; - - $.scope = new Proxy(scope, { - get(obj, prop){ - if(!obj[prop]){ - scope[prop] = []; - } - return Reflect.get(...arguments); - }, - set(obj, prop, value) { - - return Reflect.set(...arguments); - }, - }); - - var make = function(element, template){ - var result = []; - - result.splice = function(inputValue, ...args){ - //splice does all the heavy lifting by interacting with the DOM elements. - - var toProto = [...args] - - var index; - //if a string is submitted as the index, try to match it to index number - if(typeof arguments[0] === 'string'){ - index = this.indexOf( arguments[0] );//set where to start - if (index === -1) { - return []; - } - }else{ - index = arguments[0]; //set where to start - } - - toProto.unshift(index) - - var howMany = arguments[1]; //sets the amount of fields to remove - var args = Array.prototype.slice.call( arguments ); // coverts arguments into array - var toAdd = args.slice(2); // only keeps fields to add to array - - // if the starting point is higher then the total index count, start at the end - if( index > this.length ) { - index = this.length; - } - // if the starting point is negative, start form the end of the array, minus the start point - if( index < 0 ) { - index = this.length - Math.abs( index ); - } - - // if there are things to add, figure out the how many new indexes we need - if( !howMany && howMany !== 0 ) { - howMany = this.length - index; - } - //not sure why i put this here... but it does matter! - if( howMany > this.length - index ) { - howMany = this.length - index; - } - - //figure out how many positions we need to shift the current elements - var shift = toAdd.length - howMany; - - // figure out how big the new array will be - // var newLength = this.length + shift; - - //removes fields from array based on howMany needs to be removed - for( var i = index; i < +index+howMany; i++ ) { - this.__take(this[index].__jq_$el, this[index], this); - // this.__take.apply( $( '.jq-repeat-'+ this.__jqRepeatId +'[jq-repeat-index="'+ ( i + index ) +'"]' ) ); - } - - //re-factor element index's - for(var i = 0; i < this.length; i++){ - if( i >= index){ - - this[i].__jq_$el.attr( 'jq-repeat-index', i+shift ); - } - } - - //if there are fields to add to the array, add them - if( toAdd.length > 0 ){ - - //$.each( toAdd, function( key, value ){ - for(var I = 0; I < toAdd.length; I++){ - - //figure out new elements index - var key = I + index; - // apply values to template - var render = Mustache.render(this.__jqTemplate, this.__buildData(i, toAdd[I])); - - //set call name and index keys to DOM element - var $render = $( render ).addClass( 'jq-repeat-'+ this.__jqRepeatId ).attr( 'jq-repeat-index', key ); - - //if add new elements in proper stop, or after the place holder. - if( key === 0 ){ - this.$this.after( $render ); - }else{ - $( '.jq-repeat-'+ this.__jqRepeatId +'[jq-repeat-index="' + ( key -1 ) + '"]' ).after( $render ); - } - - Object.defineProperty( toAdd[I], "__jq_$el", { - value: $render, - writable: true, - enumerable: false, - configurable: true - } ); - - //animate element - this.__put($render, toAdd[I], this); - } - } - - //set and return new array - return Array.prototype.splice.apply(this, toProto); - }; - - result.push = function(){ - //add one or more objects to the array - - //set the index value, if none is set make it zero - var index = this.length || 0; - - //loop each passed object and pass it to slice - for (var i = 0 ; i < arguments.length; ++i) { - this.splice( ( index + i ), 0, arguments[i] ); - } - - //return new array length - return this.length; - }; - - result.pop = function(){ - //remove and return array element - - return this.splice( -1, 1 )[0]; - }; - - result.reverse = function() { - let hold = []; - for(let item of this){ - hold.push(item.__jq_$el.html()) - } - - for(let idx in hold.reverse()){ - this[idx].__jq_$el.html(hold[idx]); - } - - Array.prototype.reverse.apply( this ); - - return this; - }; - - result.remove = function(key, value){ - let index = this.indexOf(key, value) - if(index === -1) return; - this.splice(index, 1) - } - - result.shift = function() { - return this.splice( 0, 1 )[0]; - }; - - result.unshift = function(data){ - return this.splice(0,0, data) - } - - result.loop = function(){ - var temp = this[0]; - this.splice( 0,1 ); - this.push( temp ); - - return temp; - }; - - result.loopUp = function(){ - var temp = this[this.length-1]; - this.splice( -1, 1 ); - this.splice( 0, 0, temp ); - return temp; - }; - - result.indexOf = function( key, value ){ - if(typeof key === 'number') return key; - - if( typeof value !== 'string' ){ - value = arguments[0]; - key = this.__index; - } - for ( var index = 0; index < this.length; ++index ) { - if( this[index][key] === value ){ - - return index; - } - } - return -1; - }; - - result.update = function(key, value, data){ - //set variables using sting for index - - // If update is called with no index/key, assume its the 0 - if(typeof key === 'object'){ - if(this[0]){ - return this.update(0, key); - } - return this.splice(0, 1, key); - } - - if(typeof value !== 'string'){ - data = arguments[1]; - if(typeof key !== 'number'){ - value = arguments[0]; - key = this.__index; - } - } - - var index = this.indexOf( key, value ); - - if(index === -1) { - return []; - } - this[index] = $.extend( true, this[index], data ); - - var $render = $(Mustache.render(this.__jqTemplate, this.__buildData(index, this[index]))); - $render.attr('jq-repeat-index', index); - - this.__putUpdate(this[index].__jq_$el, $render, this[index], this); - this[index].__jq_$el = $render; - }; - - result.getByKey = function(key, value){ - return this[this.indexOf(key, value)]; - } - - // User definable helper methods - - result.__put = function($el, item, list){ - $el.show(); - }; - - result.__take = function($el, item, list){ - $el.remove(); - }; - - result.__putUpdate = function($el, $render, item, list){ - $el.replaceWith($render); - $el.show(); - }; - - result.__parseData = function(data){ - return data; - } - - // internal helper methods - - result.__buildData = function(index, data){ - return { - ...this.__parseData(data), - nestedTemplates: this.__parseNestedTemplates(index, data), - _parent: this._parentData, - }; - }; - - result.__parseNestedTemplates = function(index, data){ - let templates = [] - let tempData = { - ...data, - _parent: data, - }; - - for(let idx in this.nestedTemplates){ - let $el = $(`${this.nestedTemplates[idx]}`); - - $el.attr('jq-repeat', Mustache.render($el.attr('jq-repeat'), tempData)); - $el.attr('jq-repeat-index', Mustache.render($el.attr('jq-repeat-index'), tempData)); - $el.attr('jq-repeat-parent', this.__jqRepeatId); - $el.attr('jq-repeat-parent-index', index); - templates[idx] = $el[0].outerHTML; - } - - return templates; - } - - for(let prop of ['put', 'take', 'putUpdate', 'parseData']){ - Object.defineProperty(result, prop, { - enumerable: false, - get(){ - return this[`__${prop}`] - }, - set(value) { - this[`__${prop}`] = value; - }, - }); - } - - var $this = $(element); - result.nestedTemplates = []; - result.__jqRepeatId = $this.attr( 'jq-repeat' ); - $this.removeAttr('jq-repeat'); - result.__index = $this.attr('jq-repeat-index'); - - if($this.attr('jq-repeat-parent')){ - result._parentData = $.scope[$this.attr('jq-repeat-parent')][$this.attr('jq-repeat-parent-index')] - result.__jqParent = $this.attr('jq-repeat-parent'); - result.__jqParentIndex = $this.attr('jq-repeat-parent-index'); - } - - $this.find('[jq-repeat]').each((idx, el)=>{ - let templateIdx = result.nestedTemplates.length; - let template = `${el.outerHTML}`; - result.nestedTemplates.push(template); - $(el).replaceWith(`{{{ nestedTemplates.${templateIdx} }}}`); - }); - - result.__jqTemplate = $this[0].outerHTML; - $this.replaceWith( ' + {{/domains}}