Merge pull request #884 from bunkerity/dev

Merge branch "dev" into branch "ui"
This commit is contained in:
Théophile Diot 2024-01-23 18:17:51 +01:00 committed by GitHub
commit ee24d61de1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
512 changed files with 21853 additions and 3184 deletions

View file

@ -35,12 +35,12 @@ jobs:
python -m pip install --no-cache-dir --require-hashes -r src/common/db/requirements.txt
echo "CODEQL_PYTHON=$(which python)" >> $GITHUB_ENV
- name: Initialize CodeQL
uses: github/codeql-action/init@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12
uses: github/codeql-action/init@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
with:
languages: ${{ matrix.language }}
config-file: ./.github/codeql.yml
setup-python-dependencies: false
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12
uses: github/codeql-action/analyze@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
with:
category: "/language:${{matrix.language}}"

View file

@ -56,6 +56,8 @@ jobs:
echo "$SSH_KEY" > ~/.ssh/id_rsa_arm
chmod 600 ~/.ssh/id_rsa_arm
echo "$SSH_CONFIG" | sed "s/SSH_IP/$SSH_IP/g" > ~/.ssh/config
echo "ServerAliveInterval 60" >> ~/.ssh/config
echo "ServerAliveCountMax 10" >> ~/.ssh/config
env:
SSH_KEY: ${{ secrets.ARM_SSH_KEY }}
SSH_IP: ${{ secrets.ARM_SSH_IP }}
@ -84,7 +86,7 @@ jobs:
# Compute metadata
- name: Extract metadata
id: meta
uses: docker/metadata-action@9dc751fe249ad99385a2583ee0d084c400eee04e # v5.4.0
uses: docker/metadata-action@dbef88086f6cef02e264edb7dbf63250c17cef6c # v5.5.0
with:
images: bunkerity/${{ inputs.IMAGE }}
# Build cached image

View file

@ -46,7 +46,7 @@ jobs:
default-organization-id: ${{ secrets.SCW_DEFAULT_ORGANIZATION_ID }}
- name: Extract ARM type
run: |
TYPE=$(echo "$JSON" | jq '.servers | with_entries(select(.key | contains("AMP"))) | with_entries(select(.value.availability != "shortage")) | keys[] | select(. | test("^AMP2-C[0-9]+$")) | sub("AMP2-C"; "") | tonumber' | sort -n | tail -n 1 | xargs -I {} echo "AMP2-C{}")
TYPE=$(echo "$JSON" | jq '.servers | with_entries(select(.key | contains("COPARM1-"))) | with_entries(select(.value.availability != "shortage")) | keys[] | select(. | test("^COPARM1-[0-9]+C-[0-9]+G$"))' | sed 's/"//g' | cut -d '-' -f 2,3 | sort -g | tail -n 1 | xargs -I {} echo "COPARM1-{}")
echo "Type is $TYPE"
echo "TYPE=$TYPE" >> "$GITHUB_ENV"
env:
@ -81,6 +81,6 @@ jobs:
SSH_IP: ${{ fromJson(steps.scw.outputs.json).public_ip.address }}
SSH_CONFIG: ${{ secrets.ARM_SSH_CONFIG }}
- name: Install Docker
run: ssh root@$SSH_IP "curl -fsSL https://test.docker.com -o test-docker.sh ; sh test-docker.sh"
run: ssh root@$SSH_IP "curl -fsSL https://test.docker.com -o test-docker.sh ; sh test-docker.sh ; echo 'ClientAliveInterval 60' >> /etc/ssh/sshd_config ; echo 'ClientAliveCountMax 0' >> /etc/ssh/sshd_config ; systemctl restart ssh"
env:
SSH_IP: ${{ fromJson(steps.scw.outputs.json).public_ip.address }}

View file

@ -13,6 +13,7 @@ jobs:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
image: [bunkerweb, scheduler, autoconf, ui]
include:
@ -84,7 +85,6 @@ jobs:
# Core tests
prepare-tests-core:
needs: [build-containers, build-packages]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
@ -96,7 +96,7 @@ jobs:
outputs:
tests: ${{ steps.set-matrix.outputs.tests }}
tests-core:
needs: prepare-tests-core
needs: [build-containers, prepare-tests-core]
strategy:
fail-fast: false
matrix:
@ -106,7 +106,7 @@ jobs:
TEST: ${{ matrix.test }}
RELEASE: dev
tests-core-linux:
needs: prepare-tests-core
needs: [build-packages, prepare-tests-core]
strategy:
fail-fast: false
matrix:

View file

@ -18,8 +18,8 @@ jobs:
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: "3.10"
- name: Install doc requirements
run: pip install --no-cache-dir --require-hashes -r docs/requirements.txt
- name: Install doc dependencies
run: pip install --no-cache-dir --require-hashes -r docs/requirements.txt && sudo apt install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev
- name: Install chromium
run: sudo apt install chromium-browser
- name: Install node
@ -32,7 +32,7 @@ jobs:
run: mkdocs serve & sleep 10
- name: Run pdf script
run: node docs/misc/pdf.js http://localhost:8000/print_page/ BunkerWeb_documentation_v${{ inputs.VERSION }}.pdf 'BunkerWeb documentation v${{ inputs.VERSION }}'
- uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
- uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
with:
name: BunkerWeb_documentation_v${{ inputs.VERSION }}.pdf
path: BunkerWeb_documentation_v${{ inputs.VERSION }}.pdf

View file

@ -65,6 +65,8 @@ jobs:
echo "$SSH_KEY" > ~/.ssh/id_rsa_arm
chmod 600 ~/.ssh/id_rsa_arm
echo "$SSH_CONFIG" | sed "s/SSH_IP/$SSH_IP/g" > ~/.ssh/config
echo "ServerAliveInterval 60" >> ~/.ssh/config
echo "ServerAliveCountMax 10" >> ~/.ssh/config
env:
SSH_KEY: ${{ secrets.ARM_SSH_KEY }}
SSH_IP: ${{ secrets.ARM_SSH_IP }}
@ -127,7 +129,7 @@ jobs:
scp -r root@arm:/root/package-${{ inputs.LINUX }} ./package-${{ inputs.LINUX }}
env:
LARCH: ${{ env.LARCH }}
- uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
- uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
with:
name: package-${{ inputs.LINUX }}-${{ env.LARCH }}
path: package-${{ inputs.LINUX }}/*.${{ inputs.PACKAGE }}
@ -135,7 +137,7 @@ jobs:
- name: Extract metadata
if: inputs.TEST == true
id: meta
uses: docker/metadata-action@9dc751fe249ad99385a2583ee0d084c400eee04e # v5.4.0
uses: docker/metadata-action@dbef88086f6cef02e264edb7dbf63250c17cef6c # v5.5.0
with:
images: ghcr.io/bunkerity/${{ inputs.LINUX }}-tests:${{ inputs.RELEASE }}
- name: Build test image

View file

@ -32,8 +32,8 @@ jobs:
- uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: "3.10"
- name: Install doc requirements
run: pip install --no-cache-dir --require-hashes -r docs/requirements.txt
- name: Install doc dependencies
run: pip install --no-cache-dir --require-hashes -r docs/requirements.txt && sudo apt install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev
- name: Push doc
run: mike deploy --update-aliases --push --alias-type=copy ${{ inputs.VERSION }} ${{ inputs.ALIAS }}
- name: Set default doc

View file

@ -51,6 +51,8 @@ jobs:
echo "$SSH_KEY" > ~/.ssh/id_rsa_arm
chmod 600 ~/.ssh/id_rsa_arm
echo "$SSH_CONFIG" | sed "s/SSH_IP/$SSH_IP/g" > ~/.ssh/config
echo "ServerAliveInterval 60" >> ~/.ssh/config
echo "ServerAliveCountMax 10" >> ~/.ssh/config
env:
SSH_KEY: ${{ secrets.ARM_SSH_KEY }}
SSH_IP: ${{ secrets.ARM_SSH_IP }}
@ -63,7 +65,7 @@ jobs:
# Compute metadata
- name: Extract metadata
id: meta
uses: docker/metadata-action@9dc751fe249ad99385a2583ee0d084c400eee04e # v5.4.0
uses: docker/metadata-action@dbef88086f6cef02e264edb7dbf63250c17cef6c # v5.5.0
with:
images: bunkerity/${{ inputs.IMAGE }}
# Build and push

View file

@ -19,7 +19,7 @@ jobs:
# Get PDF doc
- name: Get documentation
if: inputs.VERSION != 'testing'
uses: actions/download-artifact@f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110 # v4.1.0
uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
with:
name: BunkerWeb_documentation_v${{ inputs.VERSION }}.pdf
# Create tag

View file

@ -42,18 +42,18 @@ jobs:
- name: Check out repository code
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install ruby
uses: ruby/setup-ruby@360dc864d5da99d54fcb8e9148c14a84b90d3e88 # v1.165.1
uses: ruby/setup-ruby@5daca165445f0ae10478593083f72ca2625e241d # v1.169.0
with:
ruby-version: "3.0"
- name: Install packagecloud
run: gem install package_cloud
# Download packages
- uses: actions/download-artifact@f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110 # v4.1.0
- uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
if: inputs.LINUX != 'el'
with:
name: package-${{ inputs.LINUX }}-${{ inputs.PACKAGE_ARCH }}
path: /tmp/${{ inputs.LINUX }}
- uses: actions/download-artifact@f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110 # v4.1.0
- uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
if: inputs.LINUX == 'el'
with:
name: package-rhel-${{ inputs.PACKAGE_ARCH }}

View file

@ -25,6 +25,6 @@ jobs:
results_format: sarif
publish_results: true
- name: "Upload SARIF results to code scanning"
uses: github/codeql-action/upload-sarif@012739e5082ff0c22ca6d6ab32e07c36df03c4a4 # v3.22.12
uses: github/codeql-action/upload-sarif@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
with:
sarif_file: results.sarif

View file

@ -55,7 +55,7 @@ jobs:
if: always()
env:
SECRET_KEY: ${{ secrets.SECRET_KEY }}
- uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
- uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
if: always()
with:
name: tf-${{ inputs.TYPE }}

View file

@ -23,7 +23,7 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install terraform
uses: hashicorp/setup-terraform@a1502cd9e758c50496cc9ac5308c4843bcd56d36 # v3.0.0
- uses: actions/download-artifact@f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110 # v4.1.0
- uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
with:
name: tf-${{ inputs.TYPE }}
path: /tmp

View file

@ -43,7 +43,7 @@ jobs:
if: inputs.TYPE == 'swarm'
- name: Install test dependencies
run: pip3 install --no-cache-dir --require-hashes --no-deps -r tests/requirements.txt
- uses: actions/download-artifact@f44cd7b40bfd40b6aa1cc1b9b5b7bf03d3c67110 # v4.1.0
- uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1
with:
name: tf-k8s
path: /tmp

View file

@ -85,7 +85,6 @@ jobs:
SECRET_KEY: ${{ secrets.SECRET_KEY }}
K8S_IP: ${{ secrets.K8S_IP }}
prepare-tests-core:
needs: [codeql, build-containers, build-packages]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
@ -130,7 +129,7 @@ jobs:
RUNS_ON: ${{ matrix.runs_on }}
secrets: inherit
tests-core:
needs: prepare-tests-core
needs: [build-containers, prepare-tests-core]
strategy:
fail-fast: false
matrix:
@ -140,7 +139,7 @@ jobs:
TEST: ${{ matrix.test }}
RELEASE: testing
tests-core-linux:
needs: prepare-tests-core
needs: [build-packages, prepare-tests-core]
strategy:
fail-fast: false
matrix:

View file

@ -97,7 +97,7 @@ jobs:
run: |
export MAKEFLAGS="-j $(nproc)"
pip install --no-cache-dir --ignore-installed --require-hashes -r src/deps/requirements-deps.txt
MAKEFLAGS="-j $(nproc)" find tests/core -name "requirements.txt" -exec pip install --no-cache-dir --require-hashes --no-deps -r {} \;
cd ./tests/core/${{ inputs.TEST }}
cd tests/core/${{ inputs.TEST }}
find . -name "requirements.txt" -exec pip install --no-cache-dir --require-hashes --no-deps -r {} \;
sudo truncate -s 0 /var/log/bunkerweb/error.log
./test.sh "linux"

View file

@ -66,14 +66,13 @@ jobs:
- name: Fix version without a starting number
if: inputs.RELEASE == 'testing' || inputs.RELEASE == 'dev' || inputs.RELEASE == 'ui'
run: echo "force-bad-version" | sudo tee -a /etc/dpkg/dpkg.cfg
- name: Install BunkerWeb
run: sudo apt install -fy /tmp/bunkerweb.deb
- name: Edit configuration files
run: |
# Misc
echo "127.0.0.1 www.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 app1.example.com" | sudo tee -a /etc/hosts
# BunkerWeb
sudo mkdir -p /etc/bunkerweb
echo "SERVER_NAME=" | sudo tee /etc/bunkerweb/variables.env
echo "HTTP_PORT=80" | sudo tee -a /etc/bunkerweb/variables.env
echo 'DNS_RESOLVERS=9.9.9.9 8.8.8.8 8.8.4.4' | sudo tee -a /etc/bunkerweb/variables.env
@ -92,6 +91,8 @@ jobs:
sudo chown nginx:nginx /etc/bunkerweb/variables.env /etc/bunkerweb/ui.env
sudo chmod 777 /etc/bunkerweb/variables.env /etc/bunkerweb/ui.env
- name: Install BunkerWeb
run: sudo apt install -fy /tmp/bunkerweb.deb
- name: Run tests
run: |
export MAKEFLAGS="-j $(nproc)"

View file

@ -1,6 +1,6 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
exclude: (^LICENSE.md$|^src/VERSION$|^env/|^src/(bw/misc/root-ca.pem$|deps/src/|common/core/modsecurity/files|ui/static/js/(editor/|utils/purify/|tsparticles\.bundle\.min\.js))|\.(svg|drawio|patch\d?|ascii|tf|tftpl|key)$)
exclude: (^LICENSE.md$|^src/VERSION$|^env/|^src/(bw/misc/root-ca.pem$|deps/src/|common/core/modsecurity/files|ui/static/(js/(editor/|utils/purify/|tsparticles\.bundle\.min\.js)|css/dashboard\.css))|\.(svg|drawio|patch\d?|ascii|tf|tftpl|key)$)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: c4a0b883114b00d8d76b479c820ce7950211c99b # frozen: v4.5.0
@ -30,7 +30,7 @@ repos:
name: Prettier Code Formatter
- repo: https://github.com/JohnnyMorganz/StyLua
rev: f9afc7f33bc19f7708fbc1d7eea0606e0d41080a # frozen: v0.19.1
rev: 84c370104d6a8d1eef00c80a3ebd42f7033aaaad # frozen: v0.20.0
hooks:
- id: stylua-github
exclude: ^src/(bw/lua/middleclass.lua|common/core/antibot/captcha.lua)$
@ -50,7 +50,7 @@ repos:
args: ["--max-line-length=250", "--ignore=E266,E402,E722,W503"]
- repo: https://github.com/dosisod/refurb
rev: a7c461fcfaa2ca3248d489cdf7fed8e2d4fd8520 # frozen: v1.26.0
rev: a295cee6d188f5797aefe5d7cf77a353ed48ea93 # frozen: v1.27.0
hooks:
- id: refurb
name: Refurb Python Refactoring Tool
@ -62,7 +62,7 @@ repos:
- id: codespell
name: Codespell Spell Checker
exclude: (^src/(ui/templates|common/core/.+/files|bw/loading)/.+.html|modsecurity-rules.conf.*)$
entry: codespell --ignore-regex="(tabEl|Widgits)" --skip src/ui/static/js/utils/flatpickr.js,CHANGELOG.md
entry: codespell --ignore-regex="(tabEl|Widgits)" --skip src/ui/static/js/utils/flatpickr.js,src/ui/static/css/style.css,CHANGELOG.md
language: python
types: [text]

View file

@ -0,0 +1 @@
CVE-2023-6129

View file

@ -1,15 +1,26 @@
# Changelog
## v1.5.5 - YYYY/MM/DD
## v1.5.6 - YYYY/MM/DD
- [BUGFIX] Fix issues with the database when upgrading from version 1.5.3 and 1.5.4 to the most recent version
- [MISC] Updated Linux base images in Dockerfiles
- [DEPS] Updated stream-lua-nginx-module to v0.0.14
- [DEPS] Updated lua-nginx-module version to v0.10.26
- [DEPS] Updated libmaxminddb version to v1.9.1
- [DEPS] Updated lua-resty-core to v0.1.28
- [DEPS] Updated zlib version to v1.3.1
## v1.5.5 - 2024/01/12
- [BUGFIX] Fix issues with the database when upgrading from one version to a newer one
- [BUGFIX] Fix ModSecurity-nginx to make it work with brotli
- [BUGFIX] Remove certbot renew delay causing errors on k8s
- [BUGFIX] Fix missing custom modsec files when BW instances change
- [BUGFIX] Fix inconsistency on config changes when using Redis
- [BUGFIX] Fix web UI not working when using / URL
- [FEATURE] Add Anonymous reporting feature
- [FEATURE] Add support for fallback Referrer-Policies
- [FEATURE] Add profile page to web ui and the possibility to activate the 2FA
- [FEATURE] Add 2FA support to web UI
- [FEATURE] Add username and password management to web UI
- [FEATURE] Add setting REVERSE_PROXY_INCLUDES to manually add "include" directives in the reverse proxies
- [FEATURE] Add support for Redis Sentinel
- [FEATURE] Add support for tls in Ingress definition
@ -17,7 +28,6 @@
- [MISC] Various internal improvements in LUA code
- [MISC] Check nginx configuration before reload
- [MISC] Updated Python Docker image to 3.12.1-alpine3.18 in Dockerfiles
- [MISC] Switch gunicorn worker_class back to gevent in web UI
- [DEPS] Updated ModSecurity to v3.0.11
## v1.5.4 - 2023/12/04

View file

@ -1,5 +1,5 @@
<p align="center">
<img alt="BunkerWeb logo" src="https://github.com/bunkerity/bunkerweb/raw/v1.5.5/misc/logo.png" />
<img alt="BunkerWeb logo" src="https://github.com/bunkerity/bunkerweb/raw/v1.5.5/misc/logo.png" height=100 width=350 />
</p>
<p align="center">

5
docs/package.json Normal file
View file

@ -0,0 +1,5 @@
{
"dependencies": {
"puppeteer": "^21.3.6"
}
}

View file

@ -1,5 +1,5 @@
mike==2.0.0
mkdocs==1.5.3
mkdocs-material[imaging]==9.5.3
mkdocs-material[imaging]==9.5.4
mkdocs-print-site-plugin==2.3.6
pytablewriter==1.2.0

View file

@ -211,81 +211,81 @@ importlib-resources==6.1.1 \
--hash=sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a \
--hash=sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6
# via mike
jinja2==3.1.2 \
--hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
--hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
jinja2==3.1.3 \
--hash=sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa \
--hash=sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90
# via
# mike
# mkdocs
# mkdocs-material
markdown==3.5.1 \
--hash=sha256:5874b47d4ee3f0b14d764324d2c94c03ea66bee56f2d929da9f2508d65e722dc \
--hash=sha256:b65d7beb248dc22f2e8a31fb706d93798093c308dc1aba295aedeb9d41a813bd
markdown==3.5.2 \
--hash=sha256:d43323865d89fc0cb9b20c75fc8ad313af307cc087e84b657d9eec768eddeadd \
--hash=sha256:e1ac7b3dc550ee80e602e71c1d168002f062e49f1b11e26a36264dafd4df2ef8
# via
# mkdocs
# mkdocs-material
# pymdown-extensions
markupsafe==2.1.3 \
--hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
--hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
--hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
--hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
--hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
--hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
--hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
--hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
--hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
--hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
--hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
--hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
--hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
--hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
--hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
--hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
--hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
--hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
--hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
--hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
--hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
--hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
--hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
--hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
--hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
--hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
--hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
--hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
--hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
--hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
--hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
--hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
--hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
--hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
--hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
--hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
--hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
--hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
--hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
--hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
--hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
--hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
--hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
--hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
--hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
--hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
--hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
--hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
--hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
--hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
--hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
--hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
--hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
--hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
--hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
--hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
--hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
--hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
--hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
--hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
markupsafe==2.1.4 \
--hash=sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69 \
--hash=sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0 \
--hash=sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d \
--hash=sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec \
--hash=sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5 \
--hash=sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411 \
--hash=sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3 \
--hash=sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74 \
--hash=sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0 \
--hash=sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949 \
--hash=sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d \
--hash=sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279 \
--hash=sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f \
--hash=sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6 \
--hash=sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc \
--hash=sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e \
--hash=sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954 \
--hash=sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656 \
--hash=sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc \
--hash=sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518 \
--hash=sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56 \
--hash=sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc \
--hash=sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa \
--hash=sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565 \
--hash=sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4 \
--hash=sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb \
--hash=sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250 \
--hash=sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4 \
--hash=sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959 \
--hash=sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc \
--hash=sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474 \
--hash=sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863 \
--hash=sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8 \
--hash=sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f \
--hash=sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2 \
--hash=sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e \
--hash=sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e \
--hash=sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb \
--hash=sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f \
--hash=sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a \
--hash=sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26 \
--hash=sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d \
--hash=sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2 \
--hash=sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131 \
--hash=sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789 \
--hash=sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6 \
--hash=sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a \
--hash=sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858 \
--hash=sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e \
--hash=sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb \
--hash=sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e \
--hash=sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84 \
--hash=sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7 \
--hash=sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea \
--hash=sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b \
--hash=sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6 \
--hash=sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475 \
--hash=sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74 \
--hash=sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a \
--hash=sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00
# via
# jinja2
# mkdocs
@ -311,9 +311,9 @@ mkdocs==1.5.3 \
# -r requirements.in
# mike
# mkdocs-material
mkdocs-material==9.5.3 \
--hash=sha256:5899219f422f0a6de784232d9d40374416302ffae3c160cacc72969fcc1ee372 \
--hash=sha256:76c93a8525cceb0b395b9cedab3428bf518cf6439adef2b940f1c1574b775d89
mkdocs-material==9.5.4 \
--hash=sha256:3d196ee67fad16b2df1a458d650a8ac1890294eaae368d26cee71bc24ad41c40 \
--hash=sha256:efd7cc8ae03296d728da9bd38f4db8b07ab61f9738a0cbd0dfaf2a15a50e7343
# via
# -r requirements.in
# mkdocs-material
@ -477,6 +477,7 @@ pyyaml==6.0.1 \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \

View file

@ -550,4 +550,3 @@ Allow access based on internal and external IP/network/rDNS/ASN whitelists.
|`WHITELIST_USER_AGENT_URLS`| |global |no |List of URLs, separated with spaces, containing good User-Agent to whitelist. |
|`WHITELIST_URI` | |multisite|no |List of URI (PCRE regex), separated with spaces, to whitelist. |
|`WHITELIST_URI_URLS` | |global |no |List of URLs, separated with spaces, containing bad URI to whitelist. |

View file

@ -465,4 +465,4 @@ In case you lost your UI credentials or have 2FA issues, you can connect to the
1|<username>|<password_hash>|0||(manual or ui)
```
You should now be able to log into the web UI only using your username and password.
You should now be able to log into the web UI only using your username and password.

View file

@ -37,7 +37,9 @@ Because the web UI is a web application, the recommended installation procedure
## Setup wizard
The setup wizard is a feature that helps you to **configure** and **install the web UI** using a **user-friendly interface**. You will need to set the `UI_HOST` setting (`http://hostname-of-web-ui:7000`) and browse the `/setup` URI of your server to access the setup wizard.
!!! info "Wizard"
The setup wizard is a feature that helps you to **configure** and **install the web UI** using a **user-friendly interface**. You will need to set the `UI_HOST` setting (`http://hostname-of-web-ui:7000`) and browse the `/setup` URI of your server to access the setup wizard.
<figure markdown>
![Overview](assets/img/ui-wizard-account.webp){ align=center, width="350" }
@ -66,6 +68,11 @@ Review your final BunkerWeb UI URL and then click on the `Setup` button. Once th
If you want to use the setup wizard, you will need to set the `UI_HOST` setting to the HTTP endpoint of your web UI container. For example, if your web UI container is named `bw-ui` and is listening on the `7000` port, you will need to set the `UI_HOST` setting to `http://bw-ui:7000`.
!!! tip "Accessing the setup wizard"
You can access the setup wizard by browsing the `http://your-ip-address/setup` URI of your server.
Here is the docker-compose boilerplate that you can use (don't forget to edit the `changeme` data) :
```yaml
@ -153,6 +160,10 @@ Review your final BunkerWeb UI URL and then click on the `Setup` button. Once th
If you want to use the setup wizard, you will need to set the `UI_HOST` setting to the HTTP endpoint of your web UI container. For example, if your web UI container is named `bw-ui` and is listening on the `7000` port, you will need to set the `UI_HOST` setting to `http://bw-ui:7000`.
!!! tip "Accessing the setup wizard"
You can access the setup wizard by browsing the `http://your-ip-address/setup` URI of your server.
Here is the docker-compose boilerplate that you can use (don't forget to edit the `changeme` data) :
```yaml
@ -256,6 +267,10 @@ Review your final BunkerWeb UI URL and then click on the `Setup` button. Once th
If you want to use the setup wizard, you will need to set the `UI_HOST` setting to the HTTP endpoint of your web UI container. For example, if your web UI container is named `bw-ui` and is listening on the `7000` port, you will need to set the `UI_HOST` setting to `http://bw-ui:7000`.
!!! tip "Accessing the setup wizard"
You can access the setup wizard by browsing the `http://your-ip-address/setup` URI of your server.
Here is the stack boilerplate that you can use (don't forget to edit the `changeme` data) :
```yaml
@ -382,6 +397,10 @@ Review your final BunkerWeb UI URL and then click on the `Setup` button. Once th
If you want to use the setup wizard, you will need to set the `UI_HOST` setting to the HTTP endpoint of your web UI SERVICE. For example, if your web UI service is named `svc-bunkerweb-ui` and is listening on the `7000` port, you will need to set the `UI_HOST` setting to `http://svc-bunkerweb-ui:7000`.
!!! tip "Accessing the setup wizard"
You can access the setup wizard by browsing the `http://your-ip-address/setup` URI of your server.
Here is the yaml boilerplate that you can use (don't forget to edit the `changeme` data) :
```yaml
@ -695,6 +714,10 @@ Review your final BunkerWeb UI URL and then click on the `Setup` button. Once th
If you want to use the setup wizard, you will need to set the `UI_HOST` setting to the HTTP endpoint of your web UI SERVICE. Since the web UI is listening on the same machine as BunkerWeb, you will need to set the `UI_HOST` setting `http://127.0.0.1:7000`.
!!! tip "Accessing the setup wizard"
You can access the setup wizard by browsing the `http://your-ip-address/setup` URI of your server.
Here is the `/etc/bunkerweb/variables.env` boilerplate you can use :
```conf
@ -772,7 +795,7 @@ The following steps are needed to enable the TOTP feature from the web UI :
- Enter your current password
!!! info "Secret key refresh"
A new secret key is **generated each time** you visit the page or submit the form. In case something went wrong (e.g. : expired TOTP code), you will need to copy the new secret key to your authenticator app until 2FA is successfuly enabled.
A new secret key is **generated each time** you visit the page or submit the form. In case something went wrong (e.g. : expired TOTP code), you will need to copy the new secret key to your authenticator app until 2FA is successfully enabled.
Once enabled, 2FA authentication can be disabled at the same place.

View file

@ -1,7 +1,7 @@
{
"name": "autoconf-configs",
"kinds": ["autoconf"],
"delay": 60,
"delay": 180,
"timeout": 60,
"tests": [
{

View file

@ -1,7 +1,7 @@
{
"name": "docker-configs",
"kinds": ["docker"],
"delay": 30,
"delay": 120,
"timeout": 60,
"tests": [
{

View file

@ -2,7 +2,7 @@
"name": "kubernetes-ingress",
"kinds": ["kubernetes"],
"timeout": 60,
"delay": 60,
"delay": 120,
"tests": [
{
"type": "string",

View file

@ -1,26 +1,29 @@
{
"name": "kubernetes-ingress",
"name": "kubernetes-tls",
"kinds": ["kubernetes"],
"timeout": 60,
"delay": 60,
"delay": 300,
"tests": [
{
"type": "string",
"url": "https://app1.example.com",
"string": "hello",
"tls": "app1.example.com,app2.example.com"
"tls": "app1.example.com,app2.example.com",
"tls_edit": false
},
{
"type": "string",
"url": "https://app2.example.com",
"string": "hello",
"tls": "app1.example.com,app2.example.com"
"tls": "app1.example.com,app2.example.com",
"tls_edit": false
},
{
"type": "string",
"url": "https://app3.example.com",
"string": "hello",
"tls": "app3.example.com"
"tls": "app3.example.com",
"tls_edit": false
}
]
}

View file

@ -1,7 +1,8 @@
{
"name": "swarm-configs",
"kinds": ["swarm"],
"timeout": 120,
"timeout": 60,
"delay": 120,
"tests": [
{
"type": "string",

View file

@ -1,3 +1,14 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-bunkerweb
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
@ -247,14 +258,3 @@ spec:
protocol: TCP
port: 6379
targetPort: 6379
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-bunkerweb
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi

View file

@ -100,10 +100,15 @@ class DockerController(Controller):
first=not self._loaded,
)
def __process_event(self, event):
return "Actor" in event and "Attributes" in event["Actor"] and ("bunkerweb.INSTANCE" in event["Actor"]["Attributes"] or "bunkerweb.SERVER_NAME" in event["Actor"]["Attributes"])
def process_events(self):
self._set_autoconf_load_db()
for _ in self.__client.events(decode=True, filters={"type": "container"}):
for event in self.__client.events(decode=True, filters={"type": "container"}):
try:
if not self.__process_event(event):
continue
self._update_settings()
self._instances = self.get_instances()
self._services = self.get_services()

View file

@ -1,4 +1,4 @@
FROM python:3.12.1-alpine3.18@sha256:af0d8da43677e3000ebdf4045508d891a87e7bd2d3ec87bc6e40403be97291b8 AS builder
FROM python:3.12.1-alpine3.18@sha256:fb759579d60cfe1f70b110a27be95aaa7cf758d2fa21cf54fffb71c2ba3f8034 AS builder
# Copy python requirements
COPY src/deps/requirements.txt /tmp/requirements-deps.txt
@ -34,7 +34,7 @@ COPY src/common/helpers helpers
COPY src/common/settings.json settings.json
COPY src/common/utils utils
FROM python:3.12.1-alpine3.18@sha256:af0d8da43677e3000ebdf4045508d891a87e7bd2d3ec87bc6e40403be97291b8
FROM python:3.12.1-alpine3.18@sha256:fb759579d60cfe1f70b110a27be95aaa7cf758d2fa21cf54fffb71c2ba3f8034
# Set default umask to prevent huge recursive chmod increasing the final image size
RUN umask 027
@ -64,7 +64,7 @@ RUN apk add --no-cache bash && \
chmod 750 cli/main.py helpers/*.sh /usr/bin/bwcli autoconf/main.py deps/python/bin/*
# Fix CVEs
# There are no CVEs to fix in this image
RUN apk add --no-cache "libcrypto3>=3.1.4-r3" "libssl3>=3.1.4-r3" "sqlite-libs>=3.41.2-r3"
VOLUME /data /etc/nginx

View file

@ -146,15 +146,16 @@ class IngressController(Controller):
for host in tls.hosts:
for service in services:
if host in service["SERVER_NAME"].split(" "):
secret_tls = self.__corev1.list_secret_for_all_namespaces(
secrets_tls = self.__corev1.list_secret_for_all_namespaces(
watch=False,
field_selector=f"metadata.name={tls.secret_name},metadata.namespace={namespace}",
).items
if not secret_tls:
if len(secrets_tls) == 0:
self._logger.warning(
f"Ignoring tls setting for {host} : secret {tls.secret_name} not found.",
)
break
secret_tls = secrets_tls[0]
if not secret_tls.data:
self._logger.warning(
f"Ignoring tls setting for {host} : secret {tls.secret_name} contains no data.",
@ -227,6 +228,22 @@ class IngressController(Controller):
configs[config_type][f"{config_site}{config_name}"] = config_data
return configs
def __process_event(self, event):
obj = event["object"]
metadata = obj.metadata if obj else None
annotations = metadata.annotations if metadata else None
if not obj:
return False
if obj.kind == "Pod":
return annotations and "bunkerweb.io/INSTANCE" in annotations
if obj.kind == "Ingress":
return True
if obj.kind == "ConfigMap":
return annotations and "bunkerweb.io/CONFIG_TYPE" in annotations
if obj.kind == "Service":
return True
return False
def __watch(self, watch_type):
w = watch.Watch()
what = None
@ -245,9 +262,13 @@ class IngressController(Controller):
locked = False
error = False
try:
for _ in w.stream(what):
for event in w.stream(what):
self.__internal_lock.acquire()
locked = True
if not self.__process_event(event):
self.__internal_lock.release()
locked = False
continue
self._update_settings()
self._instances = self.get_instances()
self._services = self.get_services()

View file

@ -16,14 +16,20 @@ class SwarmController(Controller):
super().__init__("swarm")
self.__client = DockerClient(base_url=docker_host)
self.__internal_lock = Lock()
self.__swarm_instances = []
self.__swarm_services = []
self.__swarm_configs = []
def _get_controller_instances(self) -> List[Service]:
self.__swarm_instances = []
return self.__client.services.list(filters={"label": "bunkerweb.INSTANCE"})
def _get_controller_services(self) -> List[Service]:
self.__swarm_services = []
return self.__client.services.list(filters={"label": "bunkerweb.SERVER_NAME"})
def _to_instances(self, controller_instance) -> List[dict]:
self.__swarm_instances.append(controller_instance.id)
instances = []
instance_env = {}
for env in controller_instance.attrs["Spec"]["TaskTemplate"]["ContainerSpec"]["Env"]:
@ -46,6 +52,7 @@ class SwarmController(Controller):
return instances
def _to_services(self, controller_service) -> List[dict]:
self.__swarm_services.append(controller_service.id)
service = {}
for variable, value in controller_service.attrs["Spec"]["Labels"].items():
if not variable.startswith("bunkerweb."):
@ -80,6 +87,7 @@ class SwarmController(Controller):
return services
def get_configs(self) -> Dict[str, Dict[str, Any]]:
self.__swarm_configs = []
configs = {}
for config_type in self._supported_config_types:
configs[config_type] = {}
@ -103,6 +111,7 @@ class SwarmController(Controller):
continue
config_site = f"{config.attrs['Spec']['Labels']['bunkerweb.CONFIG_SITE']}/"
configs[config_type][f"{config_site}{config_name}"] = b64decode(config.attrs["Spec"]["Data"])
self.__swarm_configs.append(config.id)
return configs
def apply_config(self) -> bool:
@ -113,14 +122,40 @@ class SwarmController(Controller):
first=not self._loaded,
)
def __process_event(self, event):
if "Actor" not in event or "ID" not in event["Actor"] or "Type" not in event:
return False
if event["Type"] not in ("service", "config"):
return False
if event["Type"] == "service":
if event["Actor"]["ID"] in self.__swarm_instances or event["Actor"]["ID"] in self.__swarm_services:
return True
try:
labels = self.__client.services.get(event["Actor"]["ID"]).attrs["Spec"]["Labels"]
return "bunkerweb.INSTANCE" in labels or "bunkerweb.SERVER_NAME" in labels
except:
return False
if event["Type"] == "config":
if event["Actor"]["ID"] in self.__swarm_configs:
return True
try:
return "bunkerweb.CONFIG_TYPE" in self.__client.configs.get(event["Actor"]["ID"]).attrs["Spec"]["Labels"]
except:
return False
return False
def __event(self, event_type):
while True:
locked = False
error = False
try:
for _ in self.__client.events(decode=True, filters={"type": event_type}):
for event in self.__client.events(decode=True, filters={"type": event_type}):
self.__internal_lock.acquire()
locked = True
if not self.__process_event(event):
self.__internal_lock.release()
locked = False
continue
try:
self._update_settings()
self._instances = self.get_instances()
@ -137,6 +172,7 @@ class SwarmController(Controller):
self._logger.info(
"Successfully deployed new configuration 🚀",
)
self._set_autoconf_load_db()
except:
self._logger.error(f"Exception while processing Swarm event ({event_type}) :\n{format_exc()}")
self.__internal_lock.release()

View file

@ -78,7 +78,7 @@ RUN apk add --no-cache pcre bash python3 yajl && \
ln -s /proc/1/fd/1 /var/log/bunkerweb/access.log
# Fix CVEs
RUN apk add --no-cache "libwebp>=1.2.4-r3" "curl>=8.3.0-r0" "libcurl>=8.3.0-r0" "nghttp2-libs>=1.51.0-r2" "libcrypto3>=3.0.12-r0" "libssl3>=3.0.12-r0" "libx11>=1.8.7-r0"
RUN apk add --no-cache "libwebp>=1.2.4-r3" "curl>=8.3.0-r0" "libcurl>=8.3.0-r0" "nghttp2-libs>=1.51.0-r2" "libx11>=1.8.7-r0" "libssl3>=3.0.12-r1" "libcrypto3>=3.0.12-r1"
EXPOSE 8080/tcp 8443/tcp

View file

@ -33,7 +33,6 @@ local get_body_data = ngx_req.get_body_data
local get_body_file = ngx_req.get_body_file
local decode = cjson.decode
local encode = cjson.encode
local floor = math.floor
local match = string.match
local require_plugin = helpers.require_plugin
local new_plugin = helpers.new_plugin
@ -216,7 +215,26 @@ api.global.POST["^/ban$"] = function(self)
if not ok then
return self:response(HTTP_INTERNAL_SERVER_ERROR, "error", "can't decode JSON : " .. ip)
end
datastore:set("bans_ip_" .. ip["ip"], "manual", ip["exp"])
local ban = {
ip = "",
exp = 86400,
reason = "manual",
}
ban.ip = ip["ip"]
if ip["exp"] then
ban.exp = ip["exp"]
end
if ip["reason"] then
ban.reason = ip["reason"]
end
datastore:set(
"bans_ip_" .. ban["ip"],
encode({
reason = ban["reason"],
date = os.time(),
}),
ban["exp"]
)
return self:response(HTTP_OK, "success", "ip " .. ip["ip"] .. " banned")
end
@ -224,12 +242,12 @@ api.global.GET["^/bans$"] = function(self)
local data = {}
for _, k in ipairs(datastore:keys()) do
if k:find("^bans_ip_") then
local reason, err = datastore:get(k)
local result, err = datastore:get(k)
if err then
return self:response(
HTTP_INTERNAL_SERVER_ERROR,
"error",
"can't access " .. k .. " from datastore : " .. reason
"can't access " .. k .. " from datastore : " .. result
)
end
local ok, ttl = datastore:ttl(k)
@ -240,7 +258,9 @@ api.global.GET["^/bans$"] = function(self)
"can't access ttl " .. k .. " from datastore : " .. ttl
)
end
local ban = { ip = k:sub(9, #k), reason = reason, exp = floor(ttl) }
local ban_data = decode(result)
local ban =
{ ip = k:sub(9, #k), reason = ban_data["reason"], date = ban_data["date"], exp = math.floor(ttl) }
table.insert(data, ban)
end
end

View file

@ -2,7 +2,6 @@ local ngx = ngx
local class = require "middleclass"
local clogger = require "bunkerweb.logger"
local rc = require "resty.redis.connector"
local rs = require("resty.redis.sentinel")
local utils = require "bunkerweb.utils"
local clusterstore = class("clusterstore")
@ -12,10 +11,10 @@ local logger = clogger:new("CLUSTERSTORE")
local get_variable = utils.get_variable
local is_cosocket_available = utils.is_cosocket_available
local ERR = ngx.ERR
local WARN = ngx.WARN
local INFO = ngx.INFO
local tonumber = tonumber
local tostring = tostring
local random = math.random
function clusterstore:initialize(pool)
-- Get variables
@ -25,6 +24,7 @@ function clusterstore:initialize(pool)
["REDIS_PORT"] = "",
["REDIS_DATABASE"] = "",
["REDIS_SSL"] = "",
["REDIS_SSL_VERIFY"] = "",
["REDIS_TIMEOUT"] = "",
["REDIS_KEEPALIVE_IDLE"] = "",
["REDIS_KEEPALIVE_POOL"] = "",
@ -57,6 +57,7 @@ function clusterstore:initialize(pool)
keepalive_poolsize = tonumber(self.variables["REDIS_KEEPALIVE_POOL"]),
connection_options = {
ssl = self.variables["REDIS_SSL"] == "yes",
ssl_verify = self.variables["REDIS_SSL_VERIFY"] == "yes",
},
host = self.variables["REDIS_HOST"],
port = tonumber(self.variables["REDIS_PORT"]),
@ -71,7 +72,6 @@ function clusterstore:initialize(pool)
}
self.pool = pool == nil or pool
if self.pool then
options.connection_options.pool = "bw-redis"
options.connection_options.pool_size = tonumber(self.variables["REDIS_KEEPALIVE_POOL"])
end
if self.variables["REDIS_SENTINEL_HOSTS"] ~= "" then
@ -82,7 +82,14 @@ function clusterstore:initialize(pool)
else
sport = tonumber(sport)
end
table.insert(options.sentinel, { host = shost, port = sport })
local data = { host = shost, port = sport }
if options.sentinel_username ~= "" then
data.username = options.sentinel_username
end
if options.sentinel_password ~= "" then
data.password = options.sentinel_password
end
table.insert(options.sentinels, data)
end
end
self.options = options
@ -107,33 +114,37 @@ function clusterstore:connect(readonly)
self:close()
end
-- Connect to sentinels if needed
local redis_client, err
if #self.options.sentinels > 0 then
local redis_sentinel
redis_sentinel, err = self.redis_connector:connect()
if not redis_sentinel then
return false, "error while connecting to sentinels : " .. err
end
if readonly then
local redis_clients, _ = rs.get_slaves(redis_sentinel, self.options.master_name)
if redis_clients then
redis_client = redis_clients[random(#redis_clients)]
else
redis_client = nil
local redis_client, err, previous_errors
if #self.options.sentinels > 0 and readonly then
redis_client, err, previous_errors = self.redis_connector:connect({ role = "slave" })
if not redis_client then
if previous_errors then
err = err .. " ( previous errors : "
for _, e in ipairs(previous_errors) do
err = err .. e .. ", "
end
err = err:sub(1, -3) .. " )"
end
else
redis_client, err = rs.get_master(redis_sentinel, self.options.master_name)
logger:log(WARN, "error while getting redis slave client : " .. err .. ", fallback to master")
redis_client, err, previous_errors = self.redis_connector:connect()
end
-- Classic connection
else
redis_client, err = self.redis_connector:connect()
redis_client, err, previous_errors = self.redis_connector:connect()
end
self.redis_client = redis_client
if not self.redis_client then
if previous_errors then
err = err .. " ( previous errors : "
for _, e in ipairs(previous_errors) do
err = err .. e .. ", "
end
err = err:sub(1, -3) .. " )"
end
return false, "error while getting redis client : " .. err
end
-- Everything went well
local times, err = self.redis_client:get_reused_times()
local times
times, err = self.redis_client:get_reused_times()
if times == nil then
self:close()
return false, "error while getting reused times : " .. err

View file

@ -15,8 +15,10 @@ if not lru then
logger:log(ERR, "failed to instantiate LRU cache : " .. err_lru)
end
function datastore:initialize()
if subsystem == "http" then
function datastore:initialize(dict)
if dict then
self.dict = dict
elseif subsystem == "http" then
self.dict = shared.datastore
else
self.dict = shared.datastore_stream
@ -112,4 +114,32 @@ function datastore:flush_lru()
lru:flush_all()
end
function datastore:safe_rpush(key, value)
local length, err = self.dict:rpush(key, value)
if not length and err == "no memory" then
local i = 0
while i < 5 do
local val
val, err = self.dict:lpop(key)
if not val then
return val, err
end
length, err = self.dict:rpush(key, value)
if not length and err ~= "no memory" then
return length, err
end
i = i + 1
end
end
return length, err
end
function datastore:lpop(key)
return self.dict:lpop(key)
end
function datastore:llen(key)
return self.dict:llen(key)
end
return datastore

View file

@ -185,6 +185,7 @@ helpers.fill_ctx = function(no_ref)
end
data.remote_addr = var.remote_addr
data.server_name = var.server_name
data.local_time = var.local_time
if data.kind == "http" then
data.uri = var.uri
data.request_uri = var.request_uri

View file

@ -29,7 +29,6 @@ local decode = cjson.decode
local char = string.char
local random = math.random
local session_start = session.start
local session_open = session.open
local tonumber = tonumber
local utils = {}
@ -569,86 +568,86 @@ utils.get_deny_status = function()
return 444
end
utils.check_session = function(ctx)
local _session, _, exists, _ = session_start({ audience = "metadata" })
utils.get_session = function(ctx)
-- Return session from ctx if already there
if ctx.bw.sessions_session then
return ctx.bw.sessions_session
end
-- Open/create and do an optional refresh
local err, exists, refreshed
session, err, exists, refreshed = session_start()
if not session then
return nil, err
end
if err then
logger:log(WARN, "can't open session : " .. err)
end
local checks = {
["IP"] = ctx.bw.remote_addr,
["USER_AGENT"] = ctx.bw.http_user_agent or "",
}
if exists then
for _, check in ipairs(ctx.bw.sessions_checks) do
local key = check[1]
local value = check[2]
if _session:get(key) ~= value then
_session:clear_request_cookie()
local ok, err = _session:destroy()
if not ok then
return false, "session:destroy() error : " .. err
logger:log(INFO, "opening an existing session")
if refreshed then
logger:log(INFO, "existing session refreshed")
end
-- Get metadata
local metadata = session:get("metadata")
if metadata then
-- Check if session passes the checks
for check, value in pairs(checks) do
local check_value
check_value, err = utils.get_variable("SESSIONS_CHECK_" .. check, false, nil)
if not check_value then
logger:log(ERR, "error while getting variable SESSIONS_CHECK_" .. check .. " : " .. err)
elseif check_value == "yes" and value ~= metadata[check] then
logger:log(WARN, "session check failed : " .. check .. "!=" .. metadata[check])
local ok
ok, err = session:destroy()
if not ok then
return nil, err
end
return utils.get_session(ctx)
end
logger:log(WARN, "session check " .. key .. " failed, destroying session")
return utils.check_session(ctx)
end
end
else
for _, check in ipairs(ctx.bw.sessions_checks) do
_session:set(check[1], check[2])
end
local ok, err = _session:save()
if not ok then
_session:close()
return false, "session:save() error : " .. err
end
logger:log(INFO, "creating a new session")
session:set("metadata", checks)
ctx.bw.sessions_updated = true
end
ctx.bw.sessions_is_checked = true
return true, exists
ctx.bw.sessions_session = session
return session
end
utils.get_session = function(audience, ctx)
-- Check session
if not ctx.bw.sessions_is_checked then
local ok, err = utils.check_session(ctx)
if not ok then
return false, "error while checking session, " .. err
utils.save_session = function(ctx)
if ctx.bw.sessions_session then
if ctx.bw.sessions_updated then
local ok, err = ctx.bw.sessions_session:save()
if not err then
err = "session saved"
end
return ok, err
else
return true, "session not updated"
end
else
return true, "no session"
end
-- Open session with specific audience
local _session, err, _ = session_open({ audience = audience })
if err then
logger:log(INFO, "session:open() error : " .. err)
end
return _session
end
-- luacheck: ignore 214
utils.get_session_data = function(_session, site, ctx)
local site_only = site == nil or site
local data = _session:get_data()
if site_only then
return data[ctx.bw.server_name] or {}
end
return data
end
-- luacheck: ignore 214
utils.set_session_data = function(_session, data, site, ctx)
local site_only = site == nil or site
if site_only then
local all_data = _session:get_data()
all_data[ctx.bw.server_name] = data
_session:set_data(all_data)
return _session:save()
end
_session:set_data(data)
return _session:save()
end
utils.is_banned = function(ip)
-- Check on local datastore
local reason, err = datastore:get("bans_ip_" .. ip)
if not reason and err ~= "not found" then
return nil, "datastore:get() error : " .. reason
elseif reason and err ~= "not found" then
local result, err = datastore:get("bans_ip_" .. ip)
if not result and err ~= "not found" then
return nil, "datastore:get() error : " .. result
elseif result and err ~= "not found" then
local ok, ttl = datastore:ttl("bans_ip_" .. ip)
local ban_data = decode(result)
if not ok then
return true, reason, -1
return true, ban_data, -1
end
return true, reason, ttl
return true, ban_data, ttl
end
-- Redis case
local use_redis, err = utils.get_variable("USE_REDIS", false)
@ -703,7 +702,11 @@ end
utils.add_ban = function(ip, reason, ttl)
-- Set on local datastore
local ok, err = datastore:set("bans_ip_" .. ip, reason, ttl)
local ban_data = encode({
reason = reason,
date = os.time(),
})
local ok, err = datastore:set("bans_ip_" .. ip, ban_data, ttl)
if not ok then
return false, "datastore:set() error : " .. err
end
@ -721,7 +724,7 @@ utils.add_ban = function(ip, reason, ttl)
return false, "can't connect to redis server : " .. err
end
-- SET call
ok, err = clusterstore:call("set", "bans_ip_" .. ip, reason, "EX", ttl)
ok, err = clusterstore:call("set", "bans_ip_" .. ip, ban_data, "EX", ttl)
if not ok then
clusterstore:close()
return false, "redis SET failed : " .. err

View file

@ -1,12 +1,15 @@
#!/usr/bin/env python3
from datetime import datetime
from json import dumps, loads
from time import time
from dotenv import dotenv_values
from os import getenv, sep
from os.path import join
from pathlib import Path
from redis import StrictRedis
from redis import StrictRedis, Sentinel
from sys import path as sys_path
from typing import Optional, Tuple
from typing import Any, Optional, Tuple
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("utils",), ("db",))]:
@ -19,10 +22,19 @@ from logger import setup_logger # type: ignore
def format_remaining_time(seconds):
days, seconds = divmod(seconds, 86400)
hours, seconds = divmod(seconds, 3600)
years, seconds = divmod(seconds, 60 * 60 * 24 * 365)
months, seconds = divmod(seconds, 60 * 60 * 24 * 30)
while months >= 12:
years += 1
months -= 12
days, seconds = divmod(seconds, 60 * 60 * 24)
hours, seconds = divmod(seconds, 60 * 60)
minutes, seconds = divmod(seconds, 60)
time_parts = []
if years > 0:
time_parts.append(f"{int(years)} year{'' if years == 1 else 's'}")
if months > 0:
time_parts.append(f"{int(months)} month{'' if months == 1 else 's'}")
if days > 0:
time_parts.append(f"{int(days)} day{'' if days == 1 else 's'}")
if hours > 0:
@ -49,6 +61,8 @@ class CLI(ApiCaller):
if Path(sep, "usr", "share", "bunkerweb", "db").exists():
from Database import Database # type: ignore
self.__logger.info("Getting variables from database")
db = Database(self.__logger, sqlalchemy_string=self.__get_variable("DATABASE_URI", None))
self.__variables = db.get_config()
@ -58,6 +72,7 @@ class CLI(ApiCaller):
self.__use_redis = self.__get_variable("USE_REDIS", "no") == "yes"
self.__redis = None
if self.__use_redis:
self.__logger.info("Fetching redis configuration")
redis_host = self.__get_variable("REDIS_HOST")
if redis_host:
redis_port = self.__get_variable("REDIS_PORT", "6379")
@ -89,16 +104,71 @@ class CLI(ApiCaller):
redis_keepalive_pool = "10"
redis_keepalive_pool = int(redis_keepalive_pool)
self.__redis = StrictRedis(
host=redis_host,
port=redis_port,
db=redis_db,
socket_timeout=redis_timeout,
socket_connect_timeout=redis_timeout,
socket_keepalive=True,
max_connections=redis_keepalive_pool,
ssl=self.__get_variable("REDIS_SSL", "no") == "yes",
)
self.__logger.info("Redis configuration is valid")
redis_ssl = self.__get_variable("REDIS_SSL", "no") == "yes"
username = self.__get_variable("REDIS_USERNAME", None) or None
password = self.__get_variable("REDIS_PASSWORD", None) or None
sentinel_hosts = self.__get_variable("REDIS_SENTINEL_HOSTS", [])
if isinstance(sentinel_hosts, str):
sentinel_hosts = [host.split(":") if ":" in host else host for host in sentinel_hosts.split(" ") if host]
if sentinel_hosts:
sentinel_username = self.__get_variable("REDIS_SENTINEL_USERNAME", None) or None
sentinel_password = self.__get_variable("REDIS_SENTINEL_PASSWORD", None) or None
sentinel_master = self.__get_variable("REDIS_SENTINEL_MASTER", "")
self.__logger.info(
f"Connecting to redis sentinel cluster with the following parameters:\n{sentinel_hosts=}\n{sentinel_username=}\n{sentinel_password=}\n{sentinel_master=}\n{redis_timeout=}\nmax_connections={redis_keepalive_pool}\n{redis_ssl=}"
)
sentinel = Sentinel(
sentinel_hosts,
username=sentinel_username,
password=sentinel_password,
ssl=redis_ssl,
socket_timeout=redis_timeout,
socket_connect_timeout=redis_timeout,
socket_keepalive=True,
max_connections=redis_keepalive_pool,
)
try:
sentinel.discover_master(sentinel_master)
except Exception as e:
self.__logger.error(f"Failed to connect to redis sentinel cluster: {e}, disabling redis")
self.__use_redis = False
if self.__use_redis:
self.__logger.info(f"Connected to redis sentinel cluster, getting master with the following parameters:\n{sentinel_master=}\n{redis_db=}\n{username=}\n{password=}")
self.__redis = sentinel.master_for(
sentinel_master,
db=redis_db,
username=username,
password=password,
)
else:
self.__logger.info(f"Connecting to redis with the following parameters:\n{redis_host=}\n{redis_port=}\n{redis_db=}\n{username=}\n{password=}\n{redis_timeout=}\nmax_connections={redis_keepalive_pool}\n{redis_ssl=}")
self.__redis = StrictRedis(
host=redis_host,
port=redis_port,
db=redis_db,
username=username,
password=password,
socket_timeout=redis_timeout,
socket_connect_timeout=redis_timeout,
socket_keepalive=True,
max_connections=redis_keepalive_pool,
ssl=redis_ssl,
)
try:
if self.__use_redis:
assert self.__redis, "Redis connection is None"
self.__redis.ping()
except Exception as e:
self.__logger.error(f"Failed to connect to redis: {e}, disabling redis")
self.__use_redis = False
self.__logger.info("Connected to redis")
else:
self.__logger.error("USE_REDIS is set to yes but REDIS_HOST is not set, disabling redis")
self.__use_redis = False
@ -116,7 +186,7 @@ class CLI(ApiCaller):
super().__init__()
self.auto_setup(self.__integration)
def __get_variable(self, variable: str, default: Optional[str] = None) -> Optional[str]:
def __get_variable(self, variable: str, default: Optional[Any] = None) -> Optional[str]:
return getenv(variable, self.__variables.get(variable, default))
def __detect_integration(self) -> str:
@ -148,14 +218,15 @@ class CLI(ApiCaller):
return True, f"IP {ip} has been unbanned"
return False, "error"
def ban(self, ip: str, exp: float) -> Tuple[bool, str]:
def ban(self, ip: str, exp: float, reason: str) -> Tuple[bool, str]:
if self.__redis:
ok = self.__redis.set(f"bans_ip_{ip}", "manual", ex=exp)
ok = self.__redis.set(f"bans_ip_{ip}", dumps({"reason": reason, "date": time()}))
if not ok:
self.__logger.error(f"Failed to ban {ip} in redis")
self.__redis.expire(f"bans_ip_{ip}", int(exp))
if self.send_to_apis("POST", "/ban", data={"ip": ip, "exp": exp}):
return (True, f"IP {ip} has been banned for {format_remaining_time(exp)}")
if self.send_to_apis("POST", "/ban", data={"ip": ip, "exp": exp, "reason": reason}):
return (True, f"IP {ip} has been banned for {format_remaining_time(exp)} with reason {reason}")
return False, "error"
def bans(self) -> Tuple[bool, str]:
@ -172,8 +243,13 @@ class CLI(ApiCaller):
servers["redis"] = []
for key in self.__redis.scan_iter("bans_ip_*"):
ip = key.decode("utf-8").replace("bans_ip_", "")
data = self.__redis.get(key)
if not data:
continue
exp = self.__redis.ttl(key)
servers["redis"].append({"ip": ip, "exp": exp, "reason": "manual"})
servers["redis"].append({"ip": ip, "exp": exp} | loads(data))
servers = {k: sorted(v, key=lambda x: x["date"]) for k, v in servers.items()}
cli_str = ""
for server, bans in servers.items():
@ -182,7 +258,7 @@ class CLI(ApiCaller):
cli_str += "No ban found\n"
for ban in bans:
cli_str += f"- {ban['ip']} for {format_remaining_time(ban['exp'])} : {ban.get('reason', 'no reason given')}\n"
cli_str += f"- {ban['ip']} ; banned the {datetime.fromtimestamp(ban['date']).strftime('%d-%m-%Y at %H:%M:%S')} for {format_remaining_time(ban['exp'])} remaining with reason \"{ban.get('reason', 'no reason given')}\"\n"
cli_str += "\n"
return True, cli_str

View file

@ -40,6 +40,12 @@ if __name__ == "__main__":
help=f"banning time in seconds (default : {ban_time})",
default=ban_time,
)
parser_ban.add_argument(
"-reason",
type=str,
help="reason for ban (default : manual)",
default="manual",
)
# Bans subparser
parser_bans = subparsers.add_parser("bans", help="list current bans")
@ -55,7 +61,7 @@ if __name__ == "__main__":
if args.command == "unban":
ret, err = cli.unban(args.ip)
elif args.command == "ban":
ret, err = cli.ban(args.ip, args.exp)
ret, err = cli.ban(args.ip, args.exp, args.reason)
elif args.command == "bans":
ret, err = cli.bans()

View file

@ -13,6 +13,11 @@ server {
# default mime type is JSON
default_type 'application/json';
# variables
set $reason '';
set $reason_data '';
set $ctx_ref '';
# check IP and do the API call
access_by_lua_block {
-- Instantiate objects and import required modules

View file

@ -1,7 +1,9 @@
server {
# reason variable
# variables
set $reason '';
set $reason_data '';
set $ctx_ref '';
server_name _;
@ -99,6 +101,8 @@ server {
local ok, ret = call_plugin(plugin_obj, "log_default")
if not ok then
logger:log(ERR, ret)
elseif not ret.ret then
logger:log(ERR, plugin_id .. ":log_default() call failed : " .. ret.msg)
else
logger:log(INFO, plugin_id .. ":log_default() call successful : " .. ret.msg)
end

View file

@ -22,6 +22,7 @@ access_by_lua_block {
local is_banned = utils.is_banned
local set_reason = utils.set_reason
local get_deny_status = utils.get_deny_status
local save_session = utils.save_session
local tostring = tostring
-- Don't process internal requests
@ -120,6 +121,14 @@ access_by_lua_block {
end
logger:log(INFO, "called access() methods of plugins")
-- Save session
ok, err = save_session(ctx)
if ok then
logger:log(INFO, err)
else
logger:log(ERR, err)
end
-- Save ctx
save_ctx(ctx)

View file

@ -85,6 +85,7 @@ ssl_certificate_by_lua_block {
if not ok then
logger:log(ERR, "error while setting private key : " .. err)
else
logger:log(INFO, "certificate set by " .. plugin_id)
return true
end
end

View file

@ -12,11 +12,10 @@ local ngx = ngx
local subsystem = ngx.config.subsystem
local HTTP_INTERNAL_SERVER_ERROR = ngx.HTTP_INTERNAL_SERVER_ERROR
local OK = ngx.OK
local INFO = ngx.INFO
local tonumber = tonumber
local tostring = tostring
local get_session = utils.get_session
local get_session_data = utils.get_session_data
local set_session_data = utils.set_session_data
local get_deny_status = utils.get_deny_status
local rand = utils.rand
local now = ngx.now
@ -46,37 +45,26 @@ function antibot:header()
return self:ret(true, "antibot not activated")
end
-- Check if antibot uri
if self.ctx.bw.uri ~= self.variables["ANTIBOT_URI"] then
return self:ret(true, "Not antibot uri")
end
-- Get session data
local session, err = get_session("antibot", self.ctx)
if not session then
return self:ret(false, "can't get session : " .. err, HTTP_INTERNAL_SERVER_ERROR)
end
self.session = session
self.session_data = get_session_data(self.session, true, self.ctx)
-- Check if session is valid
self:check_session()
-- Don't go further if client resolved the challenge
if self.session_data.resolved then
if self.ctx.bw.uri == self.variables["ANTIBOT_URI"] then
return self:ret(true, "client already resolved the challenge", nil, self.session_data.original_uri)
end
return self:ret(true, "client already resolved the challenge")
end
if self.ctx.bw.uri ~= self.variables["ANTIBOT_URI"] then
return self:ret(true, "not antibot uri")
end
-- Get session data
self.session_data = self.ctx.bw.antibot_session_data
if not self.session_data then
return self:ret(false, "can't get session data", HTTP_INTERNAL_SERVER_ERROR)
end
-- Don't go further if client resolved the challenge
if self.session_data.resolved then
return self:ret(true, "client already resolved the challenge", nil, self.session_data.original_uri)
end
-- Override headers
local header = "Content-Security-Policy"
if self.variables["CONTENT_SECURITY_POLICY_REPORT_ONLY"] == "yes" then
header = header .. "-Report-Only"
end
if self.session_data.type == "recaptcha" then
ngx.header[header] = "default-src 'none'; form-action 'self'; script-src 'strict-dynamic' 'nonce-"
.. self.session_data.nonce_script
@ -108,7 +96,7 @@ function antibot:header()
.. self.session_data.nonce_style
.. "'; font-src 'self' data:; base-uri 'self';"
end
return self:ret(true, "Successfully overridden CSP header")
return self:ret(true, "successfully overridden CSP header")
end
function antibot:access()
@ -118,14 +106,17 @@ function antibot:access()
end
-- Get session data
local session, err = get_session("antibot", self.ctx)
local session, err = get_session(self.ctx)
if not session then
return self:ret(false, "can't get session : " .. err, HTTP_INTERNAL_SERVER_ERROR)
return self:ret(false, "can't get session : " .. err)
end
self.session = session
self.session_data = get_session_data(self.session, true, self.ctx)
self.session_data = session:get("antibot") or {}
self.ctx.bw.antibot_session_data = self.session_data
-- Check if session is valid
self:check_session()
local msg = self:check_session()
self.logger:log(INFO, "check_session returned : " .. msg)
-- Don't go further if client resolved the challenge
if self.session_data.resolved then
@ -137,10 +128,6 @@ function antibot:access()
-- Prepare challenge if needed
self:prepare_challenge()
local ok, err = self:set_session_data()
if not ok then
return self:ret(false, "can't save session : " .. err, HTTP_INTERNAL_SERVER_ERROR)
end
-- Redirect to challenge page
if self.ctx.bw.uri ~= self.variables["ANTIBOT_URI"] then
@ -162,10 +149,6 @@ function antibot:access()
if self.ctx.bw.request_method == "POST" then
-- luacheck: ignore 421
local ok, err, redirect = self:check_challenge()
local set_ok, set_err = self:set_session_data()
if not set_ok then
return self:ret(false, "can't save session : " .. set_err, HTTP_INTERNAL_SERVER_ERROR)
end
if ok == nil then
return self:ret(false, "check challenge error : " .. err, HTTP_INTERNAL_SERVER_ERROR)
elseif not ok then
@ -175,10 +158,6 @@ function antibot:access()
return self:ret(true, "check challenge redirect : " .. redirect, nil, redirect)
end
self:prepare_challenge()
ok, err = self:set_session_data()
if not ok then
return self:ret(false, "can't save session : " .. err, HTTP_INTERNAL_SERVER_ERROR)
end
self.ctx.bw.antibot_display_content = true
return self:ret(true, "displaying challenge to client", OK)
end
@ -202,12 +181,10 @@ function antibot:content()
end
-- Get session data
local session, err = get_session("antibot", self.ctx)
if not session then
return self:ret(false, "can't get session : " .. err, HTTP_INTERNAL_SERVER_ERROR)
self.session_data = self.ctx.bw.antibot_session_data
if not self.session_data then
return self:ret(false, "missing session data", HTTP_INTERNAL_SERVER_ERROR)
end
self.session = session
self.session_data = get_session_data(self.session, true, self.ctx)
-- Direct access without session
if not self.session_data.prepared then
@ -229,42 +206,36 @@ function antibot:check_session()
-- Not resolved and not prepared
if not time_resolve and not time_valid then
self.session_data = {}
self.session_updated = true
return
self:set_session_data()
return "not prepared"
end
-- Check if still valid
local time = ngx.now()
local time = now()
local resolved = self.session_data.resolved
if resolved and (time_valid > time or time - time_valid > tonumber(self.variables["ANTIBOT_TIME_VALID"])) then
self.session_data = {}
self.session_updated = true
return
self:set_session_data()
return "need new resolve"
end
-- Check if new prepare is needed
if
not resolved and (time_resolve > time or time - time_resolve > tonumber(self.variables["ANTIBOT_TIME_RESOLVE"]))
then
self.session_data = {}
self.session_updated = true
return
self:set_session_data()
return "need new prepare"
end
return "valid"
end
function antibot:set_session_data()
if self.session_updated then
local ok, err = set_session_data(self.session, self.session_data, true, self.ctx)
if not ok then
return false, err
end
self.session_updated = false
return true, "updated"
end
return true, "no update"
self.session:set("antibot", self.session_data)
self.ctx.bw.antibot_session_data = self.session_data
self.ctx.bw.sessions_updated = true
end
function antibot:prepare_challenge()
if not self.session_data.prepared then
self.session_updated = true
self.session_data.prepared = true
self.session_data.time_resolve = ngx.now()
self.session_data.type = self.variables["USE_ANTIBOT"]
@ -283,6 +254,7 @@ function antibot:prepare_challenge()
elseif self.session_data.type == "captcha" then
self.session_data.captcha = rand(6, true)
end
self:set_session_data()
end
end
@ -363,6 +335,7 @@ function antibot:check_challenge()
end
self.session_data.resolved = true
self.session_data.time_valid = now()
self:set_session_data()
return true, "resolved", self.session_data.original_uri
end
@ -374,10 +347,11 @@ function antibot:check_challenge()
return nil, "missing challenge arg", nil
end
if self.session_data.captcha ~= args["captcha"] then
return false, "wrong value", nil
return false, "wrong value, expected " .. self.session_data.captcha, nil
end
self.session_data.resolved = true
self.session_data.time_valid = now()
self:set_session_data()
return true, "resolved", self.session_data.original_uri
end
@ -417,6 +391,7 @@ function antibot:check_challenge()
end
self.session_data.resolved = true
self.session_data.time_valid = now()
self:set_session_data()
return true, "resolved", self.session_data.original_uri
end
@ -456,6 +431,7 @@ function antibot:check_challenge()
end
self.session_data.resolved = true
self.session_data.time_valid = now()
self:set_session_data()
return true, "resolved", self.session_data.original_uri
end
@ -495,6 +471,7 @@ function antibot:check_challenge()
end
self.session_data.resolved = true
self.session_data.time_valid = now()
self:set_session_data()
return true, "resolved", self.session_data.original_uri
end

View file

@ -250,6 +250,7 @@
class="mt-3 px-2 text-gray-800 h-8 w-full max-w-[300px] rounded-lg outline-secondary"
type="text"
name="captcha"
required
/>
<button
class="hover:brightness-90 mt-2 rounded-lg bg-secondary px-6 py-2 text-white text-sm xs:text-base font-bold"

View file

@ -137,10 +137,6 @@ function bunkernet:access()
if not self:is_needed() then
return self:ret(true, "service doesn't use BunkerNet, skipping access")
end
-- Check id
if not self.bunkernet_id then
return self:ret(false, "missing instance ID")
end
-- Check if IP is global
if not self.ctx.bw.ip_is_global then
return self:ret(true, "IP is not global")
@ -149,6 +145,10 @@ function bunkernet:access()
if is_whitelisted(self.ctx) then
return self:ret(true, "client is whitelisted")
end
-- Check id
if not self.bunkernet_id then
return self:ret(false, "missing instance ID")
end
-- Extract DB
local db, err = self.datastore:get("plugin_bunkernet_db", true)
if db then
@ -175,10 +175,6 @@ function bunkernet:log(bypass_checks)
if not self:is_needed() then
return self:ret(true, "service doesn't use BunkerNet, skipping log")
end
-- Check id
if not self.bunkernet_id then
return self:ret(false, "missing instance ID")
end
end
-- Check if IP has been blocked
local reason, reason_data = get_reason(self.ctx)
@ -192,6 +188,10 @@ function bunkernet:log(bypass_checks)
if not self.ctx.bw.ip_is_global then
return self:ret(true, "IP is not global")
end
-- Check id
if not self.bunkernet_id then
return self:ret(false, "missing instance ID")
end
-- Check if IP has been reported recently
local ok, data = self.cachestore:get("plugin_bunkernet_" .. self.ctx.bw.remote_addr .. "_" .. reason)
if not ok then
@ -239,10 +239,6 @@ function bunkernet:log_default()
if not self:is_needed() then
return self:ret(true, "no service uses BunkerNet, skipping log_default")
end
-- Check id
if not self.bunkernet_id then
return self:ret(false, "missing instance ID")
end
-- Check if default server is disabled
local check, err = get_variable("DISABLE_DEFAULT_SERVER", false)
if check == nil then

View file

@ -32,12 +32,7 @@ try:
bunkernet_activated = False
# Multisite case
if getenv("MULTISITE", "no") == "yes":
servers = getenv("SERVER_NAME") or []
if isinstance(servers, str):
servers = servers.split(" ")
for first_server in servers:
for first_server in getenv("SERVER_NAME", "").split(" "):
if getenv(f"{first_server}_USE_BUNKERNET", getenv("USE_BUNKERNET", "yes")) == "yes":
bunkernet_activated = True
break

View file

@ -36,8 +36,8 @@ function customcert:init()
for server_name, multisite_vars in pairs(vars) do
if multisite_vars["USE_CUSTOM_SSL"] == "yes" and server_name ~= "global" then
local check, data = read_files({
"/var/cache/bunkerweb/customcert/" .. server_name .. "/cert.pem",
"/var/cache/bunkerweb/customcert/" .. server_name .. "/key.pem",
"/var/cache/bunkerweb/customcert/" .. server_name .. ".cert.pem",
"/var/cache/bunkerweb/customcert/" .. server_name .. ".key.pem",
})
if not check then
self.logger:log(ERR, "error while reading files : " .. data)
@ -60,8 +60,8 @@ function customcert:init()
return self:ret(false, "can't get SERVER_NAME variable : " .. err)
end
local check, data = read_files({
"/var/cache/bunkerweb/customcert/" .. server_name:match("%S+") .. "/cert.pem",
"/var/cache/bunkerweb/customcert/" .. server_name:match("%S+") .. "/key.pem",
"/var/cache/bunkerweb/customcert/" .. server_name:match("%S+") .. ".cert.pem",
"/var/cache/bunkerweb/customcert/" .. server_name:match("%S+") .. ".key.pem",
})
if not check then
self.logger:log(ERR, "error while reading files : " .. data)
@ -87,15 +87,11 @@ function customcert:ssl_certificate()
if not server_name then
return self:ret(false, "can't get server_name : " .. err)
end
if self.variables["USE_CUSTOM_SSL"] == "yes" then
local data
data, err = self.datastore:get("plugin_customcert_" .. server_name, true)
if not data then
return self:ret(
false,
"error while getting plugin_customcert_" .. server_name .. " from datastore : " .. err
)
end
local data
data, err = self.datastore:get("plugin_customcert_" .. server_name, true)
if not data and err ~= "not found" then
return self:ret(false, "error while getting plugin_customcert_" .. server_name .. " from datastore : " .. err)
elseif data then
return self:ret(true, "certificate/key data found", data)
end
return self:ret(true, "custom certificate is not used")

View file

@ -18,7 +18,7 @@ for deps_path in [
if deps_path not in sys_path:
sys_path.append(deps_path)
from jobs import cache_file, cache_hash, file_hash
from jobs import del_file_in_db, cache_file, cache_hash, file_hash
from Database import Database # type: ignore
from logger import setup_logger # type: ignore
@ -28,6 +28,7 @@ db = None
def check_cert(cert_path: str, key_path: str, first_server: str) -> bool:
try:
ret = False
if not cert_path or not key_path:
logger.warning("Both variables CUSTOM_SSL_CERT and CUSTOM_SSL_KEY have to be set to use custom certificates")
return False
@ -48,19 +49,17 @@ def check_cert(cert_path: str, key_path: str, first_server: str) -> bool:
"cache",
"bunkerweb",
"customcert",
first_server,
"cert.pem",
f"{first_server}.cert.pem",
)
cert_cache_path.parent.mkdir(parents=True, exist_ok=True)
cert_hash = file_hash(cert_path)
old_hash = cache_hash(cert_cache_path, db)
if old_hash == cert_hash:
return False
cached, err = cache_file(cert_path, cert_cache_path, cert_hash, db, delete_file=False)
if not cached:
logger.error(f"Error while caching custom-cert cert.pem file : {err}")
if old_hash != cert_hash:
ret = True
cached, err = cache_file(cert_path, cert_cache_path, cert_hash, db, delete_file=False)
if not cached:
logger.error(f"Error while caching custom-cert cert.pem file : {err}")
key_cache_path = Path(
sep,
@ -68,19 +67,19 @@ def check_cert(cert_path: str, key_path: str, first_server: str) -> bool:
"cache",
"bunkerweb",
"customcert",
first_server,
"key.pem",
f"{first_server}.key.pem",
)
key_cache_path.parent.mkdir(parents=True, exist_ok=True)
key_hash = file_hash(key_path)
old_hash = cache_hash(key_cache_path, db)
if old_hash != key_hash:
ret = True
cached, err = cache_file(key_path, key_cache_path, key_hash, db, delete_file=False)
if not cached:
logger.error(f"Error while caching custom-cert key.pem file : {err}")
return True
return ret
except:
logger.error(
f"Exception while running custom-cert.py (check_cert) :\n{format_exc()}",
@ -103,9 +102,8 @@ try:
cert_data = b64decode(getenv("CUSTOM_SSL_CERT_DATA", ""))
key_data = b64decode(getenv("CUSTOM_SSL_KEY_DATA", ""))
for file, data in (("cert.pem", cert_data), ("key.pem", key_data)):
if data != b"":
file_path = Path(sep, "var", "tmp", "bunkerweb", "customcert", first_server, file)
file_path.parent.mkdir(parents=True, exist_ok=True)
if data:
file_path = Path(sep, "var", "tmp", "bunkerweb", "customcert", f"{first_server}.{file}")
file_path.write_bytes(data)
if file == "cert.pem":
cert_path = str(file_path)
@ -120,7 +118,28 @@ try:
status = 1
else:
logger.info(f"No change for certificate {cert_path}")
elif not cert_path or not key_path:
logger.warning("Both variables CUSTOM_SSL_CERT and CUSTOM_SSL_KEY (or CUSTOM_SSL_CERT_DATA and CUSTOM_SSL_KEY_DATA) have to be set to use custom certificates, clearing cache ...")
cert_cache_path = Path(
sep,
"var",
"cache",
"bunkerweb",
"customcert",
f"{first_server}.cert.pem",
)
cert_cache_path.unlink(missing_ok=True)
del_file_in_db(f"{first_server}.cert.pem", db, service_id=first_server)
key_cache_path = Path(
sep,
"var",
"cache",
"bunkerweb",
"customcert",
f"{first_server}.key.pem",
)
key_cache_path.unlink(missing_ok=True)
del_file_in_db(f"{first_server}.key.pem", db, service_id=first_server)
elif getenv("MULTISITE", "no") == "yes":
servers = getenv("SERVER_NAME") or []
@ -141,7 +160,7 @@ try:
key_data = b64decode(getenv(f"{first_server}_CUSTOM_SSL_KEY_DATA", ""))
for file, data in (("cert.pem", cert_data), ("key.pem", key_data)):
if data != b"":
file_path = Path(sep, "var", "tmp", "bunkerweb", "customcert", first_server, file)
file_path = Path(sep, "var", "tmp", "bunkerweb", "customcert", f"{first_server}.{file}")
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_bytes(data)
if file == "cert.pem":
@ -163,6 +182,28 @@ try:
logger.info(
f"No change for certificate {cert_path}",
)
elif not cert_path or not key_path:
logger.warning("Both variables CUSTOM_SSL_CERT and CUSTOM_SSL_KEY (or CUSTOM_SSL_CERT_DATA and CUSTOM_SSL_KEY_DATA) have to be set to use custom certificates, clearing cache ...")
cert_cache_path = Path(
sep,
"var",
"cache",
"bunkerweb",
"customcert",
f"{first_server}.cert.pem",
)
cert_cache_path.unlink(missing_ok=True)
del_file_in_db(f"{first_server}.cert.pem", db)
key_cache_path = Path(
sep,
"var",
"cache",
"bunkerweb",
"customcert",
f"{first_server}.key.pem",
)
key_cache_path.unlink(missing_ok=True)
del_file_in_db(f"{first_server}.key.pem", db)
except:
status = 2
logger.error(f"Exception while running custom-cert.py :\n{format_exc()}")

View file

@ -100,15 +100,11 @@ function letsencrypt:ssl_certificate()
if not server_name then
return self:ret(false, "can't get server_name : " .. err)
end
if self.variables["AUTO_LETS_ENCRYPT"] == "yes" then
local data
data, err = self.datastore:get("plugin_letsencrypt_" .. server_name, true)
if not data then
return self:ret(
false,
"error while getting plugin_letsencrypt_" .. server_name .. " from datastore : " .. err
)
end
local data
data, err = self.datastore:get("plugin_letsencrypt_" .. server_name, true)
if not data and err ~= "not found" then
return self:ret(false, "error while getting plugin_letsencrypt_" .. server_name .. " from datastore : " .. err)
elseif data then
return self:ret(true, "certificate/key data found", data)
end
return self:ret(true, "let's encrypt is not used")
@ -175,9 +171,9 @@ function letsencrypt:api()
if not ok then
return self:ret(true, "can't remove validation token : " .. err, HTTP_INTERNAL_SERVER_ERROR)
end
return true, HTTP_OK, { status = "success", msg = "validation token removed" }
return self:ret(true, "validation token removed", HTTP_OK)
end
return true, HTTP_NOT_FOUND, { status = "error", msg = "unknown request" }
return self:ret(true, "unknown request", HTTP_NOT_FOUND)
end
return letsencrypt

View file

@ -0,0 +1 @@
lua_shared_dict metrics_datastore {{ METRICS_MEMORY_SIZE }};

View file

@ -0,0 +1 @@
lua_shared_dict metrics_datastore_stream {{ METRICS_MEMORY_SIZE }};

View file

@ -0,0 +1,107 @@
local cjson = require "cjson"
local class = require "middleclass"
local datastore = require "datastore"
local plugin = require "bunkerweb.plugin"
local utils = require "bunkerweb.utils"
local metrics = class("metrics", plugin)
local ngx = ngx
local shared = ngx.shared
local subsystem = ngx.config.subsystem
local ERR = ngx.ERR
local HTTP_INTERNAL_SERVER_ERROR = ngx.HTTP_INTERNAL_SERVER_ERROR
local HTTP_OK = ngx.HTTP_OK
local get_reason = utils.get_reason
local get_country = utils.get_country
local encode = cjson.encode
local decode = cjson.decode
local match = string.match
function metrics:initialize(ctx)
-- Call parent initialize
plugin.initialize(self, "metrics", ctx)
local dict
if subsystem == "http" then
dict = shared.metrics_datastore
else
dict = shared.metrics_datastore_stream
end
self.metrics_datastore = datastore:new(dict)
end
function metrics:log()
-- Don't go further if metrics is not enabled
if self.variables["USE_METRICS"] == "no" then
return self:ret(true, "metrics are disabled")
end
-- Store blocked requests
local reason, data = get_reason(self.ctx)
if reason then
local country = "local"
local err
if self.ctx.bw.ip_is_global then
country, err = get_country(self.ctx.bw.remote_addr)
if not country then
country = "unknown"
self.logger:log(ERR, "can't get country code " .. err)
end
end
local request = {
date = self.ctx.bw.local_time,
ip = self.ctx.bw.remote_addr,
country = country,
method = self.ctx.bw.request_method,
url = self.ctx.bw.request_uri,
code = ngx.status,
["user-agent"] = self.ctx.bw.http_user_agent or "",
reason = reason,
data = data,
}
local ok
ok, err = self.metrics_datastore:safe_rpush("metrics_requests", encode(request))
if not ok then
self.logger:log(ERR, "can't save request to datastore : " .. err)
end
end
return self:ret(true, "success")
end
function metrics:log_default()
return self:log()
end
function metrics:api()
-- Match request
if not match(self.ctx.bw.uri, "^/metrics/requests$") or self.ctx.bw.request_method ~= "GET" then
return self:ret(false, "success")
end
-- Get requests metrics
local len, err = self.metrics_datastore:llen("metrics_requests")
if not len then
return self:ret(true, "error while getting length of metrics_requests : " .. err, HTTP_INTERNAL_SERVER_ERROR)
end
local i = 0
local data = {}
while i < len do
local request
request, err = self.metrics_datastore:lpop("metrics_requests")
if request then
table.insert(data, decode(request))
else
return self:ret(true, "error while getting metrics_requests : " .. err, HTTP_INTERNAL_SERVER_ERROR)
end
local ok
ok, err = self.metrics_datastore:safe_rpush("metrics_requests", request)
if not ok then
self.logger:log(ERR, "can't save request to datastore : " .. err)
end
i = i + 1
end
return self:ret(true, data, HTTP_OK)
end
return metrics

View file

@ -0,0 +1,27 @@
{
"id": "metrics",
"name": "Metrics",
"description": "Metrics collection and retrieve.",
"version": "1.0",
"stream": "partial",
"settings": {
"USE_METRICS": {
"context": "global",
"default": "yes",
"help": "Enable collection and retrieval of internal metrics.",
"id": "use-metrics",
"label": "Use metrics",
"regex": "^(yes|no)$",
"type": "check"
},
"METRICS_MEMORY_SIZE": {
"context": "global",
"default": "16m",
"help": "Size of the internal storage for metrics.",
"id": "metrics-memory-size",
"label": "Metrics memory size",
"regex": "^\\d+[kKmMgG]?$",
"type": "text"
}
}
}

View file

@ -32,7 +32,7 @@
"antibot"
],
"headers": ["headers", "cors", "reverseproxy", "clientcache", "antibot"],
"log": ["badbehavior", "bunkernet"],
"log": ["badbehavior", "bunkernet", "metrics"],
"preread": [
"whitelist",
"blacklist",
@ -42,5 +42,5 @@
"reversescan"
],
"log_stream": ["badbehavior", "bunkernet"],
"log_default": ["badbehavior", "bunkernet"]
"log_default": ["badbehavior", "bunkernet", "metrics"]
}

View file

@ -50,6 +50,15 @@
"regex": "^(yes|no)$",
"type": "check"
},
"REDIS_SSL_VERIFY": {
"context": "global",
"default": "no",
"help": "Verify the certificate of Redis server.",
"id": "redis-ssl-verify",
"label": "Redis SSL/TLS verify",
"regex": "^(yes|no)$",
"type": "check"
},
"REDIS_TIMEOUT": {
"context": "global",
"default": "1000",

View file

@ -87,18 +87,14 @@ function selfsigned:ssl_certificate()
if not server_name then
return self:ret(false, "can't get server_name : " .. err)
end
if self.variables["GENERATE_SELF_SIGNED_SSL"] == "yes" then
local data
data, err = self.datastore:get("plugin_selfsigned_" .. server_name, true)
if not data then
return self:ret(
false,
"error while getting plugin_selfsigned_" .. server_name .. " from datastore : " .. err
)
end
local data
data, err = self.datastore:get("plugin_selfsigned_" .. server_name, true)
if not data and err ~= "not found" then
return self:ret(false, "error while getting plugin_selfsigned_" .. server_name .. " from datastore : " .. err)
elseif data then
return self:ret(true, "certificate/key data found", data)
end
return self:ret(true, "selfsigned is not used")
return self:ret(true, "self signed is not used")
end
function selfsigned:load_data(data, server_name)

View file

@ -58,6 +58,7 @@ function sessions:init()
["REDIS_PORT"] = "",
["REDIS_DATABASE"] = "",
["REDIS_SSL"] = "",
["REDIS_SSL_VERIFY"] = "",
["REDIS_TIMEOUT"] = "",
["REDIS_KEEPALIVE_IDLE"] = "",
["REDIS_KEEPALIVE_POOL"] = "",
@ -121,9 +122,9 @@ function sessions:init()
send_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
read_timeout = tonumber(redis_vars["REDIS_TIMEOUT"]),
keepalive_timeout = tonumber(redis_vars["REDIS_KEEPALIVE_IDLE"]),
pool = "bw-redis",
pool_size = tonumber(redis_vars["REDIS_KEEPALIVE_POOL"]),
ssl = redis_vars["REDIS_SSL"] == "yes",
ssl_verify = redis_vars["REDIS_SSL_VERIFY"] == "yes",
database = tonumber(redis_vars["REDIS_DATABASE"]),
}
if redis_vars["REDIS_SENTINEL_HOSTS"] ~= nil then

View file

@ -54,7 +54,7 @@ install_as_MySQLdb()
class Database:
DB_STRING_RX = re_compile(r"^(?P<database>(mariadb|mysql)(\+pymysql)?|sqlite(\+pysqlite)?|postgresql):/+(?P<path>/[^\s]+)")
DB_STRING_RX = re_compile(r"^(?P<database>(mariadb|mysql)(\+pymysql)?|sqlite(\+pysqlite)?|postgresql(\+psycopg)?):/+(?P<path>/[^\s]+)")
def __init__(
self,
@ -85,6 +85,10 @@ class Database:
sleep(1)
else:
db_path.parent.mkdir(parents=True, exist_ok=True)
elif match.group("database").startswith("m") and not match.group("database").endswith("+pymysql"):
sqlalchemy_string = sqlalchemy_string.replace(match.group("database"), f"{match.group('database')}+pymysql") # ? This is mandatory for alemic to work with mariadb and mysql
elif match.group("database").startswith("postgresql") and not match.group("database").endswith("+psycopg"):
sqlalchemy_string = sqlalchemy_string.replace(match.group("database"), f"{match.group('database')}+psycopg") # ? This is strongly recommended as psycopg is the new way to connect to postgresql
self.database_uri = sqlalchemy_string
error = False
@ -1039,10 +1043,10 @@ class Database:
return ""
def delete_job_cache(self, file_name: str, *, job_name: Optional[str] = None):
def delete_job_cache(self, file_name: str, *, job_name: Optional[str] = None, service_id: Optional[str] = None):
job_name = job_name or basename(getsourcefile(_getframe(1))).replace(".py", "")
with self.__db_session() as session:
session.query(Jobs_cache).filter_by(job_name=job_name, file_name=file_name).delete()
session.query(Jobs_cache).filter_by(job_name=job_name, file_name=file_name, service_id=service_id).delete()
def update_job_cache(
self,

View file

@ -97,7 +97,7 @@ class Global_values(Base):
ForeignKey("bw_settings.id", onupdate="cascade", ondelete="cascade"),
primary_key=True,
)
value = Column(String(4096), nullable=False)
value = Column(String(8192), nullable=False)
suffix = Column(Integer, primary_key=True, nullable=True, default=0)
method = Column(METHODS_ENUM, nullable=False)
@ -128,7 +128,7 @@ class Services_settings(Base):
ForeignKey("bw_settings.id", onupdate="cascade", ondelete="cascade"),
primary_key=True,
)
value = Column(String(4096), nullable=False)
value = Column(String(8192), nullable=False)
suffix = Column(Integer, primary_key=True, nullable=True, default=0)
method = Column(METHODS_ENUM, nullable=False)

View file

@ -1,4 +1,4 @@
cryptography==41.0.7
psycopg2-binary==2.9.9
cryptography==42.0.0
psycopg[binary,pool]==3.1.17
PyMySQL==1.1.0
sqlalchemy==2.0.25

View file

@ -58,30 +58,39 @@ cffi==1.16.0 \
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
# via cryptography
cryptography==41.0.7 \
--hash=sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960 \
--hash=sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a \
--hash=sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc \
--hash=sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a \
--hash=sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf \
--hash=sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1 \
--hash=sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39 \
--hash=sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406 \
--hash=sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a \
--hash=sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a \
--hash=sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c \
--hash=sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be \
--hash=sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15 \
--hash=sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2 \
--hash=sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d \
--hash=sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157 \
--hash=sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003 \
--hash=sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248 \
--hash=sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a \
--hash=sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec \
--hash=sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309 \
--hash=sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7 \
--hash=sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d
cryptography==42.0.0 \
--hash=sha256:0a68bfcf57a6887818307600c3c0ebc3f62fbb6ccad2240aa21887cda1f8df1b \
--hash=sha256:146e971e92a6dd042214b537a726c9750496128453146ab0ee8971a0299dc9bd \
--hash=sha256:14e4b909373bc5bf1095311fa0f7fcabf2d1a160ca13f1e9e467be1ac4cbdf94 \
--hash=sha256:206aaf42e031b93f86ad60f9f5d9da1b09164f25488238ac1dc488334eb5e221 \
--hash=sha256:3005166a39b70c8b94455fdbe78d87a444da31ff70de3331cdec2c568cf25b7e \
--hash=sha256:324721d93b998cb7367f1e6897370644751e5580ff9b370c0a50dc60a2003513 \
--hash=sha256:33588310b5c886dfb87dba5f013b8d27df7ffd31dc753775342a1e5ab139e59d \
--hash=sha256:35cf6ed4c38f054478a9df14f03c1169bb14bd98f0b1705751079b25e1cb58bc \
--hash=sha256:3ca482ea80626048975360c8e62be3ceb0f11803180b73163acd24bf014133a0 \
--hash=sha256:56ce0c106d5c3fec1038c3cca3d55ac320a5be1b44bf15116732d0bc716979a2 \
--hash=sha256:5a217bca51f3b91971400890905a9323ad805838ca3fa1e202a01844f485ee87 \
--hash=sha256:678cfa0d1e72ef41d48993a7be75a76b0725d29b820ff3cfd606a5b2b33fda01 \
--hash=sha256:69fd009a325cad6fbfd5b04c711a4da563c6c4854fc4c9544bff3088387c77c0 \
--hash=sha256:6cf9b76d6e93c62114bd19485e5cb003115c134cf9ce91f8ac924c44f8c8c3f4 \
--hash=sha256:74f18a4c8ca04134d2052a140322002fef535c99cdbc2a6afc18a8024d5c9d5b \
--hash=sha256:85f759ed59ffd1d0baad296e72780aa62ff8a71f94dc1ab340386a1207d0ea81 \
--hash=sha256:87086eae86a700307b544625e3ba11cc600c3c0ef8ab97b0fda0705d6db3d4e3 \
--hash=sha256:8814722cffcfd1fbd91edd9f3451b88a8f26a5fd41b28c1c9193949d1c689dc4 \
--hash=sha256:8fedec73d590fd30c4e3f0d0f4bc961aeca8390c72f3eaa1a0874d180e868ddf \
--hash=sha256:9515ea7f596c8092fdc9902627e51b23a75daa2c7815ed5aa8cf4f07469212ec \
--hash=sha256:988b738f56c665366b1e4bfd9045c3efae89ee366ca3839cd5af53eaa1401bce \
--hash=sha256:a2a8d873667e4fd2f34aedab02ba500b824692c6542e017075a2efc38f60a4c0 \
--hash=sha256:bd7cf7a8d9f34cc67220f1195884151426ce616fdc8285df9054bfa10135925f \
--hash=sha256:bdce70e562c69bb089523e75ef1d9625b7417c6297a76ac27b1b8b1eb51b7d0f \
--hash=sha256:be14b31eb3a293fc6e6aa2807c8a3224c71426f7c4e3639ccf1a2f3ffd6df8c3 \
--hash=sha256:be41b0c7366e5549265adf2145135dca107718fa44b6e418dc7499cfff6b4689 \
--hash=sha256:c310767268d88803b653fffe6d6f2f17bb9d49ffceb8d70aed50ad45ea49ab08 \
--hash=sha256:c58115384bdcfe9c7f644c72f10f6f42bed7cf59f7b52fe1bf7ae0a622b3a139 \
--hash=sha256:c640b0ef54138fde761ec99a6c7dc4ce05e80420262c20fa239e694ca371d434 \
--hash=sha256:ca20550bb590db16223eb9ccc5852335b48b8f597e2f6f0878bbfd9e7314eb17 \
--hash=sha256:d97aae66b7de41cdf5b12087b5509e4e9805ed6f562406dfcf60e8481a9a28f8 \
--hash=sha256:e9326ca78111e4c645f7e49cbce4ed2f3f85e17b61a563328c85a5208cf34440
# via -r requirements.in
greenlet==3.0.3 \
--hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \
@ -143,80 +152,83 @@ greenlet==3.0.3 \
--hash=sha256:fd096eb7ffef17c456cfa587523c5f92321ae02427ff955bebe9e3c63bc9f0da \
--hash=sha256:fe754d231288e1e64323cfad462fcee8f0288654c10bdf4f603a39ed923bef33
# via sqlalchemy
psycopg2-binary==2.9.9 \
--hash=sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9 \
--hash=sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77 \
--hash=sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e \
--hash=sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84 \
--hash=sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3 \
--hash=sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2 \
--hash=sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67 \
--hash=sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876 \
--hash=sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152 \
--hash=sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f \
--hash=sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a \
--hash=sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6 \
--hash=sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503 \
--hash=sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f \
--hash=sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493 \
--hash=sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996 \
--hash=sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f \
--hash=sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e \
--hash=sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59 \
--hash=sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94 \
--hash=sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7 \
--hash=sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682 \
--hash=sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420 \
--hash=sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae \
--hash=sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291 \
--hash=sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe \
--hash=sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980 \
--hash=sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93 \
--hash=sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692 \
--hash=sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119 \
--hash=sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716 \
--hash=sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472 \
--hash=sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b \
--hash=sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2 \
--hash=sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc \
--hash=sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c \
--hash=sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5 \
--hash=sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab \
--hash=sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984 \
--hash=sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9 \
--hash=sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf \
--hash=sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0 \
--hash=sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f \
--hash=sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212 \
--hash=sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb \
--hash=sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be \
--hash=sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90 \
--hash=sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041 \
--hash=sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7 \
--hash=sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860 \
--hash=sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d \
--hash=sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245 \
--hash=sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27 \
--hash=sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417 \
--hash=sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359 \
--hash=sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202 \
--hash=sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0 \
--hash=sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7 \
--hash=sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba \
--hash=sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1 \
--hash=sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd \
--hash=sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07 \
--hash=sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98 \
--hash=sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55 \
--hash=sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d \
--hash=sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972 \
--hash=sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f \
--hash=sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e \
--hash=sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26 \
--hash=sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957 \
--hash=sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53 \
--hash=sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52
# via -r requirements.in
psycopg==3.1.17 \
--hash=sha256:437e7d7925459f21de570383e2e10542aceb3b9cb972ce957fdd3826ca47edc6 \
--hash=sha256:96b7b13af6d5a514118b759a66b2799a8a4aa78675fa6bb0d3f7d52d67eff002
# via
# -r requirements.in
# psycopg
psycopg-binary==3.1.17 \
--hash=sha256:00377f6963ee7e4bf71cab17c2c235ef0624df9483f3b615d86aa24cde889d42 \
--hash=sha256:0227885686c2cc0104ceb22d6eebc732766e9ad48710408cb0123237432e5435 \
--hash=sha256:02ac573f5a6e79bb6df512b3a6279f01f033bbd45c47186e8872fee45f6681d0 \
--hash=sha256:02cd2eb62ffc56f8c847d68765cbf461b3d11b438fe48951e44b6c563ec27d18 \
--hash=sha256:0340ef87a888fd940796c909e038426f4901046f61856598582a817162c64984 \
--hash=sha256:0b1ec6895cab887b92c303565617f994c9b9db53befda81fa2a31b76fe8a3ab1 \
--hash=sha256:12eab8bc91b4ba01b2ecee3b5b80501934b198f6e1f8d4b13596f3f38ba6e762 \
--hash=sha256:267a82548c21476120e43dc72b961f1af52c380c0b4c951bdb34cf14cb26bd35 \
--hash=sha256:2a05400e9314fc30bc1364865ba9f6eaa2def42b5e7e67f71f9a4430f870023e \
--hash=sha256:2b2a689eaede08cf91a36b10b0da6568dd6e4669200f201e082639816737992b \
--hash=sha256:3d0d154c780cc7b28a3a0886e8a4b18689202a1dbb522b3c771eb3a1289cf7c3 \
--hash=sha256:3e2cc2bbf37ff1cf11e8b871c294e3532636a3cf7f0c82518b7537158923d77b \
--hash=sha256:40af298b209dd77ca2f3e7eb3fbcfb87a25999fc015fcd14140bde030a164c7e \
--hash=sha256:420c1eb1626539c261cf3fbe099998da73eb990f9ce1a34da7feda414012ea5f \
--hash=sha256:4b20013051f1fd7d02b8d0766cfe8d009e8078babc00a6d39bc7e2d50a7b96af \
--hash=sha256:4fa26836ce074a1104249378727e1f239a01530f36bae16e77cf6c50968599b4 \
--hash=sha256:5ccbe8b2ec444763a51ecb1213befcbb75defc1ef36e7dd5dff501a23d7ce8cf \
--hash=sha256:5f5f5bcbb772d8c243d605fc7151beec760dd27532d42145a58fb74ef9c5fbf2 \
--hash=sha256:61104b8e7a43babf2bbaa36c08e31a12023e2f967166e99d6b052b11a4c7db06 \
--hash=sha256:67a5b93101bc85a95a189c0a23d02a29cf06c1080a695a0dedfdd50dd734662a \
--hash=sha256:6a728beefd89b430ebe2729d04ba10e05036b5e9d01648da60436000d2fcd242 \
--hash=sha256:6b2ae342d69684555bfe77aed5546d125b4a99012e0b83a8b3da68c8829f0935 \
--hash=sha256:6b40fa54a02825d3d6a8009d9a82a2b4fad80387acf2b8fd6d398fd2813cb2d9 \
--hash=sha256:6d4f2e15d33ed4f9776fdf23683512d76f4e7825c4b80677e9e3ce6c1b193ff2 \
--hash=sha256:6e3543edc18553e31a3884af3cd7eea43d6c44532d8b9b16f3e743cdf6cfe6c5 \
--hash=sha256:704f6393d758b12a4369887fe956b2a8c99e4aced839d9084de8e3f056015d40 \
--hash=sha256:73e7097b81cad9ae358334e3cec625246bb3b8013ae6bb287758dd6435e12f65 \
--hash=sha256:751b31c2faae0348f87f22b45ef58f704bdcfc2abdd680fa0c743c124071157e \
--hash=sha256:78ebb43dca7d5b41eee543cd005ee5a0256cecc74d84acf0fab4f025997b837e \
--hash=sha256:7b4e4c2b05f3b431e9026e82590b217e87696e7a7548f512ae8059d59fa8af3b \
--hash=sha256:7e28024204dc0c61094268c682041d2becfedfea2e3b46bed5f6138239304d98 \
--hash=sha256:83404a353240fdff5cfe9080665fdfdcaa2d4d0c5112e15b0a2fe2e59200ed57 \
--hash=sha256:86bb3656c8d744cc1e42003414cd6c765117d70aa23da6c0f4ff2b826e0fd0fd \
--hash=sha256:8c5c38129cc79d7e3ba553035b9962a442171e9f97bb1b8795c0885213f206f3 \
--hash=sha256:9124b6db07e8d8b11f4512b8b56cbe136bf1b7d0417d1280e62291a9dcad4408 \
--hash=sha256:914254849486e14aa931b0b3382cd16887f1507068ffba775cbdc5a55fe9ef19 \
--hash=sha256:92fad8f1aa80a5ab316c0493dc6d1b54c1dba21937e43eea7296ff4a0ccc071e \
--hash=sha256:93921178b9a40c60c26e47eb44970f88c49fe484aaa3bb7ec02bb8b514eab3d9 \
--hash=sha256:9690a535d9ccd361bbc3590bfce7fe679e847f44fa7cc97f3b885f4744ca8a2c \
--hash=sha256:a0c4ba73f9e7721dd6cc3e6953016652dbac206f654229b7a1a8ac182b16e689 \
--hash=sha256:a16abab0c1abc58feb6ab11d78d0f8178a67c3586bd70628ec7c0218ec04c4ef \
--hash=sha256:a343261701a8f63f0d8268f7fd32be40ffe28d24b65d905404ca03e7281f7bb5 \
--hash=sha256:a3f1196d76860e72d338fab0d2b6722e8d47e2285d693e366ae36011c4a5898a \
--hash=sha256:a880e4113af3ab84d6a0991e3f85a2424924c8a182733ab8d964421df8b5190a \
--hash=sha256:a89f36bf7b612ff6ed3e789bd987cbd0787cf0d66c49386fa3bad816dd7bee87 \
--hash=sha256:adb670031b27949c9dc5cf585c4a5a6b4469d3879fd2fb9d39b6d53e5f66b9bc \
--hash=sha256:b0711e46361ea3047cd049868419d030c8236a9dea7e9ed1f053cbd61a853ec9 \
--hash=sha256:b447ea765e71bc33a82cf070bba814b1efa77967442d116b95ccef8ce5da7631 \
--hash=sha256:bf424d92dd7e94705b31625b02d396297a7c8fab4b6f7de8dba6388323a7b71c \
--hash=sha256:c10b7713e3ed31df7319c2a72d5fea5a2536476d7695a3e1d18a1f289060997c \
--hash=sha256:c8a46f77ba0ca7c5a5449b777170a518fa7820e1710edb40e777c9798f00d033 \
--hash=sha256:ca1757a6e080086f7234dc45684e81a47a66a6dd492a37d6ce38c58a1a93e9ff \
--hash=sha256:d01c4faae66de60fcd3afd3720dcc8ffa03bc2087f898106da127774db12aac5 \
--hash=sha256:d1c0115bdf80cf6c8c9109cb10cf6f650fd1a8d841f884925e8cb12f34eb5371 \
--hash=sha256:d2e9ed88d9a6a475c67bf70fc8285e88ccece0391727c7701e5a512e0eafbb05 \
--hash=sha256:d54bcf2dfc0880bf13f38512d44b194c092794e4ee9e01d804bc6cd3eed9bfb7 \
--hash=sha256:d613a23f8928f30acb2b6b2398cb7775ba9852e8968e15df13807ba0d3ebd565 \
--hash=sha256:d90c0531e9d591bde8cea04e75107fcddcc56811b638a34853436b23c9a3cb7d \
--hash=sha256:dceb3930ec426623c0cacc78e447a90882981e8c49d6fea8d1e48850e24a0170 \
--hash=sha256:e1e867c2a729348df218a14ba1b862e627177fd57c7b4f3db0b4c708f6d03696 \
--hash=sha256:e6ae27b0617ad3809449964b5e901b21acff8e306abacb8ba71d5ee7c8c47eeb \
--hash=sha256:ea425a8dcd808a7232a5417d2633bfa543da583a2701b5228e9e29989a50deda \
--hash=sha256:f4028443bf25c1e04ecffdc552c0a98d826903dec76a1568dfddf5ebbbb03db7 \
--hash=sha256:f6898bf1ca5aa01115807643138e3e20ec603b17a811026bc4a49d43055720a7 \
--hash=sha256:f9ba559eabb0ba1afd4e0504fa0b10e00a212cac0c4028b8a1c3b087b5c1e5de
# via psycopg
psycopg-pool==3.2.1 \
--hash=sha256:060b551d1b97a8d358c668be58b637780b884de14d861f4f5ecc48b7563aafb7 \
--hash=sha256:6509a75c073590952915eddbba7ce8b8332a440a31e77bba69561483492829ad
# via psycopg
pycparser==2.21 \
--hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
--hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
@ -279,4 +291,7 @@ sqlalchemy==2.0.25 \
typing-extensions==4.9.0 \
--hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \
--hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd
# via sqlalchemy
# via
# psycopg
# psycopg-pool
# sqlalchemy

View file

@ -1,6 +1,5 @@
docker==7.0.0
jinja2==3.1.2
kubernetes==28.1.0
python-dotenv==1.0.0
jinja2==3.1.3
kubernetes==29.0.0
python-dotenv==1.0.1
redis==5.0.1
urllib3<2.0.0

View file

@ -114,83 +114,83 @@ docker==7.0.0 \
--hash=sha256:12ba681f2777a0ad28ffbcc846a69c31b4dfd9752b47eb425a274ee269c5e14b \
--hash=sha256:323736fb92cd9418fc5e7133bc953e11a9da04f4483f828b527db553f1e7e5a3
# via -r requirements.in
google-auth==2.26.1 \
--hash=sha256:2c8b55e3e564f298122a02ab7b97458ccfcc5617840beb5d0ac757ada92c9780 \
--hash=sha256:54385acca5c0fbdda510cd8585ba6f3fcb06eeecf8a6ecca39d3ee148b092590
google-auth==2.26.2 \
--hash=sha256:3f445c8ce9b61ed6459aad86d8ccdba4a9afed841b2d1451a11ef4db08957424 \
--hash=sha256:97327dbbf58cccb58fc5a1712bba403ae76668e64814eb30f7316f7e27126b81
# via kubernetes
idna==3.6 \
--hash=sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca \
--hash=sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f
# via requests
jinja2==3.1.2 \
--hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
--hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
jinja2==3.1.3 \
--hash=sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa \
--hash=sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90
# via -r requirements.in
kubernetes==28.1.0 \
--hash=sha256:10f56f8160dcb73647f15fafda268e7f60cf7dbc9f8e46d52fcd46d3beb0c18d \
--hash=sha256:1468069a573430fb1cb5ad22876868f57977930f80a6749405da31cd6086a7e9
kubernetes==29.0.0 \
--hash=sha256:ab8cb0e0576ccdfb71886366efb102c6a20f268d817be065ce7f9909c631e43e \
--hash=sha256:c4812e227ae74d07d53c88293e564e54b850452715a59a927e7e1bc6b9a60459
# via -r requirements.in
markupsafe==2.1.3 \
--hash=sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e \
--hash=sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e \
--hash=sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431 \
--hash=sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686 \
--hash=sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c \
--hash=sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559 \
--hash=sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc \
--hash=sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb \
--hash=sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939 \
--hash=sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c \
--hash=sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0 \
--hash=sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4 \
--hash=sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9 \
--hash=sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575 \
--hash=sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba \
--hash=sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d \
--hash=sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd \
--hash=sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3 \
--hash=sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00 \
--hash=sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155 \
--hash=sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac \
--hash=sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52 \
--hash=sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f \
--hash=sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8 \
--hash=sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b \
--hash=sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007 \
--hash=sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24 \
--hash=sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea \
--hash=sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198 \
--hash=sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0 \
--hash=sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee \
--hash=sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be \
--hash=sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2 \
--hash=sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1 \
--hash=sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707 \
--hash=sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6 \
--hash=sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c \
--hash=sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58 \
--hash=sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823 \
--hash=sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779 \
--hash=sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636 \
--hash=sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c \
--hash=sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad \
--hash=sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee \
--hash=sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc \
--hash=sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2 \
--hash=sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48 \
--hash=sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7 \
--hash=sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e \
--hash=sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b \
--hash=sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa \
--hash=sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5 \
--hash=sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e \
--hash=sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb \
--hash=sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9 \
--hash=sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57 \
--hash=sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc \
--hash=sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc \
--hash=sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2 \
--hash=sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11
markupsafe==2.1.4 \
--hash=sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69 \
--hash=sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0 \
--hash=sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d \
--hash=sha256:15866d7f2dc60cfdde12ebb4e75e41be862348b4728300c36cdf405e258415ec \
--hash=sha256:1c98c33ffe20e9a489145d97070a435ea0679fddaabcafe19982fe9c971987d5 \
--hash=sha256:21e7af8091007bf4bebf4521184f4880a6acab8df0df52ef9e513d8e5db23411 \
--hash=sha256:23984d1bdae01bee794267424af55eef4dfc038dc5d1272860669b2aa025c9e3 \
--hash=sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74 \
--hash=sha256:3583a3a3ab7958e354dc1d25be74aee6228938312ee875a22330c4dc2e41beb0 \
--hash=sha256:36d7626a8cca4d34216875aee5a1d3d654bb3dac201c1c003d182283e3205949 \
--hash=sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d \
--hash=sha256:3a66c36a3864df95e4f62f9167c734b3b1192cb0851b43d7cc08040c074c6279 \
--hash=sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f \
--hash=sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6 \
--hash=sha256:47bb5f0142b8b64ed1399b6b60f700a580335c8e1c57f2f15587bd072012decc \
--hash=sha256:49a3b78a5af63ec10d8604180380c13dcd870aba7928c1fe04e881d5c792dc4e \
--hash=sha256:4df98d4a9cd6a88d6a585852f56f2155c9cdb6aec78361a19f938810aa020954 \
--hash=sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656 \
--hash=sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc \
--hash=sha256:54635102ba3cf5da26eb6f96c4b8c53af8a9c0d97b64bdcb592596a6255d8518 \
--hash=sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56 \
--hash=sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc \
--hash=sha256:698e84142f3f884114ea8cf83e7a67ca8f4ace8454e78fe960646c6c91c63bfa \
--hash=sha256:6aa5e2e7fc9bc042ae82d8b79d795b9a62bd8f15ba1e7594e3db243f158b5565 \
--hash=sha256:7653fa39578957bc42e5ebc15cf4361d9e0ee4b702d7d5ec96cdac860953c5b4 \
--hash=sha256:765f036a3d00395a326df2835d8f86b637dbaf9832f90f5d196c3b8a7a5080cb \
--hash=sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250 \
--hash=sha256:7a07f40ef8f0fbc5ef1000d0c78771f4d5ca03b4953fc162749772916b298fc4 \
--hash=sha256:8b570a1537367b52396e53325769608f2a687ec9a4363647af1cded8928af959 \
--hash=sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc \
--hash=sha256:9896fca4a8eb246defc8b2a7ac77ef7553b638e04fbf170bff78a40fa8a91474 \
--hash=sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863 \
--hash=sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8 \
--hash=sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f \
--hash=sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2 \
--hash=sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e \
--hash=sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e \
--hash=sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb \
--hash=sha256:b0fe73bac2fed83839dbdbe6da84ae2a31c11cfc1c777a40dbd8ac8a6ed1560f \
--hash=sha256:b6f14a9cd50c3cb100eb94b3273131c80d102e19bb20253ac7bd7336118a673a \
--hash=sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26 \
--hash=sha256:b835aba863195269ea358cecc21b400276747cc977492319fd7682b8cd2c253d \
--hash=sha256:bf1196dcc239e608605b716e7b166eb5faf4bc192f8a44b81e85251e62584bd2 \
--hash=sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131 \
--hash=sha256:c7556bafeaa0a50e2fe7dc86e0382dea349ebcad8f010d5a7dc6ba568eaaa789 \
--hash=sha256:c8f253a84dbd2c63c19590fa86a032ef3d8cc18923b8049d91bcdeeb2581fbf6 \
--hash=sha256:d18b66fe626ac412d96c2ab536306c736c66cf2a31c243a45025156cc190dc8a \
--hash=sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858 \
--hash=sha256:d5c31fe855c77cad679b302aabc42d724ed87c043b1432d457f4976add1c2c3e \
--hash=sha256:d6e427c7378c7f1b2bef6a344c925b8b63623d3321c09a237b7cc0e77dd98ceb \
--hash=sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e \
--hash=sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84 \
--hash=sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7 \
--hash=sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea \
--hash=sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b \
--hash=sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6 \
--hash=sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475 \
--hash=sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74 \
--hash=sha256:fc1a75aa8f11b87910ffd98de62b29d6520b6d6e8a3de69a70ca34dea85d2a8a \
--hash=sha256:fe8512ed897d5daf089e5bd010c3dc03bb1bdae00b35588c49b98268d4a01e00
# via jinja2
oauthlib==3.2.2 \
--hash=sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca \
@ -216,9 +216,9 @@ python-dateutil==2.8.2 \
--hash=sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86 \
--hash=sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9
# via kubernetes
python-dotenv==1.0.0 \
--hash=sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba \
--hash=sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a
python-dotenv==1.0.1 \
--hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \
--hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a
# via -r requirements.in
pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
@ -250,6 +250,7 @@ pyyaml==6.0.1 \
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
--hash=sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba \
--hash=sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8 \
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
--hash=sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5 \
--hash=sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd \
--hash=sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3 \
@ -297,11 +298,10 @@ six==1.16.0 \
# via
# kubernetes
# python-dateutil
urllib3==1.26.18 \
--hash=sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07 \
--hash=sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0
urllib3==2.1.0 \
--hash=sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3 \
--hash=sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54
# via
# -r requirements.in
# docker
# kubernetes
# requests

View file

@ -6,7 +6,7 @@ from hashlib import sha512
from inspect import getsourcefile
from io import BufferedReader
from json import dumps, loads
from os.path import basename, normpath
from os.path import basename
from pathlib import Path
from sys import _getframe
from threading import Lock
@ -28,17 +28,19 @@ def is_cached_file(
expire: Union[Literal["hour"], Literal["day"], Literal["week"], Literal["month"]],
db=None,
) -> bool:
if not isinstance(file, Path):
file = Path(file)
is_cached = False
cached_file = None
try:
file = normpath(file)
file_path = Path(f"{file}.md")
if not file_path.is_file():
if not db:
return False
cached_file = db.get_job_cache_file(
basename(getsourcefile(_getframe(1))).replace(".py", ""),
basename(file),
file.name,
with_info=True,
)
@ -65,16 +67,13 @@ def is_cached_file(
is_cached = False
if is_cached and cached_file:
Path(file).write_bytes(cached_file.data)
file.write_bytes(cached_file.data)
return is_cached and cached_file
def get_file_in_db(file: Union[str, Path], db, *, job_name: Optional[str] = None) -> Optional[bytes]:
cached_file = db.get_job_cache_file(
job_name or basename(getsourcefile(_getframe(1))).replace(".py", ""),
normpath(file),
)
cached_file = db.get_job_cache_file(job_name or basename(getsourcefile(_getframe(1))).replace(".py", ""), file)
if not cached_file:
return None
return cached_file.data
@ -107,10 +106,10 @@ def set_file_in_db(
return ret, err
def del_file_in_db(name: str, db) -> Tuple[bool, str]:
def del_file_in_db(name: str, db, *, service_id: Optional[str] = None) -> Tuple[bool, str]:
ret, err = True, "success"
try:
db.delete_job_cache(name, job_name=basename(getsourcefile(_getframe(1))).replace(".py", ""))
db.delete_job_cache(name, job_name=basename(getsourcefile(_getframe(1))).replace(".py", ""), service_id=service_id)
except:
return False, f"exception :\n{format_exc()}"
return ret, err
@ -118,7 +117,10 @@ def del_file_in_db(name: str, db) -> Tuple[bool, str]:
def file_hash(file: Union[str, Path]) -> str:
_sha512 = sha512()
with open(normpath(file), "rb") as f:
if not isinstance(file, Path):
file = Path(file)
with file.open("rb") as f:
while True:
data = f.read(1024)
if not data:
@ -139,18 +141,24 @@ def bytes_hash(bio: BufferedReader) -> str:
def cache_hash(cache: Union[str, Path], db=None) -> Optional[str]:
checksum = None
with suppress(BaseException):
return loads(Path(normpath(f"{cache}.md")).read_text(encoding="utf-8")).get("checksum", None)
if db:
checksum = loads(Path(f"{cache}.md").read_text(encoding="utf-8")).get("checksum", None)
if not checksum and db:
if not isinstance(cache, Path):
cache = Path(cache)
cached_file = db.get_job_cache_file(
basename(getsourcefile(_getframe(1))).replace(".py", ""),
basename(normpath(cache)),
cache.name,
with_info=True,
with_data=False,
)
checksum = cached_file.checksum if cached_file else None
if cached_file:
return cached_file.checksum
if checksum:
return checksum
return None
@ -166,9 +174,9 @@ def cache_file(
ret, err = True, "success"
try:
if not isinstance(file, Path):
file = Path(normpath(file))
file = Path(file)
if not isinstance(cache, Path):
cache = Path(normpath(cache))
cache = Path(cache)
content = file.read_bytes()
cache.write_bytes(content)
@ -181,7 +189,7 @@ def cache_file(
if db:
return set_file_in_db(
basename(str(cache)),
cache.name,
content,
db,
job_name=basename(getsourcefile(_getframe(1))).replace(".py", ""),

View file

@ -71,9 +71,9 @@
},
{
"id": "libmaxminddb",
"name": "libmaxminddb v1.8.0",
"name": "libmaxminddb v1.9.1",
"url": "https://github.com/maxmind/libmaxminddb.git",
"commit": "93a7e0e5627686deb82aa636376f53b1c7af3d9a"
"commit": "e26013e1d2b57eff0ed22b7364270358adb72205"
},
{
"id": "lua-cjson",
@ -96,15 +96,15 @@
},
{
"id": "lua-nginx-module",
"name": "lua-nginx-module v0.10.25",
"name": "lua-nginx-module v0.10.26",
"url": "https://github.com/openresty/lua-nginx-module.git",
"commit": "c47084b5d719ce507d2419d8660f39544a9d1fea"
"commit": "0e769b76432df91e5f10aa56a56858e8a190faf7"
},
{
"id": "lua-resty-core",
"name": "lua-resty-core v0.1.27",
"name": "lua-resty-core v0.1.28",
"url": "https://github.com/openresty/lua-resty-core.git",
"commit": "31fae862a1ed64033591f991fadb0dd80358ba0b"
"commit": "812b2d3871eb0d8da8f0198759ad9164f0eccac6"
},
{
"id": "lua-resty-dns",
@ -225,15 +225,15 @@
},
{
"id": "stream-lua-nginx-module",
"name": "stream-lua-nginx-module v0.0.13",
"name": "stream-lua-nginx-module v0.0.14",
"url": "https://github.com/openresty/stream-lua-nginx-module.git",
"commit": "309198abf26266f1a3e53c71388ed7bb9d1e5ea2"
"commit": "cafa6f55333541d1c78767a286fa434c97574a4c"
},
{
"id": "zlib",
"name": "zlib v1.3",
"name": "zlib v1.3.1",
"url": "https://github.com/madler/zlib.git",
"commit": "09155eaa2f9270dc4ed1fa13e2b4b2613e6e4851"
"commit": "51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf"
},
{
"id": "lua-resty-redis-connector",

View file

@ -52,8 +52,8 @@ do
post="yes"
else
echo "⚠️ Skipping clone of $url because target directory is already present"
# echo " Updating ${name} from $url at commit/version $commit"
# do_and_check_cmd git subtree pull --prefix "src/deps/src/$id" "$url" "$commit" --squash
echo " Updating ${name} from $url at commit/version $commit"
do_and_check_cmd git subtree pull --prefix "src/deps/src/$id" "$url" "$commit" --squash
fi
if [ -d "src/deps/src/$id/.git" ] ; then

View file

@ -2,6 +2,8 @@ name: "Code scanning - action"
on:
push:
branches-ignore:
- 'dependabot/**'
pull_request:
schedule:
- cron: '0 7 * * 2'
@ -27,7 +29,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
- run: sudo apt install libipc-run3-perl libipc-system-simple-perl libfile-slurp-perl libfile-which-perl pandoc
- run: |
@ -37,4 +39,4 @@ jobs:
make safedist
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3

View file

@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.9)
project(maxminddb
LANGUAGES C
VERSION 1.8.0
VERSION 1.9.1
)
set(MAXMINDDB_SOVERSION 0.0.7)
set(CMAKE_C_STANDARD 99)
@ -37,8 +37,8 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
configure_file(${PROJECT_SOURCE_DIR}/include/maxminddb_config.h.cmake.in
${PROJECT_SOURCE_DIR}/include/maxminddb_config.h)
configure_file(${PROJECT_SOURCE_DIR}/include/maxminddb_config.h.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/generated/maxminddb_config.h)
add_library(maxminddb
src/maxminddb.c
@ -79,12 +79,14 @@ endif()
target_include_directories(maxminddb PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/generated/>
$<INSTALL_INTERFACE:include>
$<INSTALL_INTERFACE:generated>
)
set(MAXMINDB_HEADERS
include/maxminddb.h
include/maxminddb_config.h
${CMAKE_CURRENT_BINARY_DIR}/generated/maxminddb_config.h
)
set_target_properties(maxminddb PROPERTIES PUBLIC_HEADER "${MAXMINDB_HEADERS}")

View file

@ -1,3 +1,19 @@
## 1.9.1 - 2024-01-09
* `SSIZE_MAX` is now defined conditionally on Windows. The 1.9.0
release would cause a redefinition warning when compiled with MinGW.
Reported by Andreas Vögele. GitHub #338.
## 1.9.0 - 2024-01-09
* On very large databases, the calculation to determine the search tree
size could overflow. This was fixed and several additional guards
against overflows were added. Reported by Sami Salonen. GitHub #335.
* Removed `sa_family_t` typedef from the public header on Windows. Pull
request by Noah Treuhaft. GitHub #334.
* The CMake build was adjusted to allow running builds in parallel.
Pull request by Vladyslav Miachkov. GitHub #332.
## 1.8.0 - 2023-11-07
* `PACKAGE_VERSION` is now a private compile definition when building

View file

@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.63])
AC_INIT([libmaxminddb], [1.8.0], [support@maxmind.com])
AC_INIT([libmaxminddb], [1.9.1], [support@maxmind.com])
AC_CONFIG_SRCDIR([include/maxminddb.h])
AC_CONFIG_HEADERS([config.h include/maxminddb_config.h])

View file

@ -17,8 +17,6 @@ extern "C" {
#include <ws2tcpip.h>
/* libmaxminddb package version from configure */
typedef ADDRESS_FAMILY sa_family_t;
#if defined(_MSC_VER)
/* MSVC doesn't define signed size_t, copy it from configure */
#define ssize_t SSIZE_T

View file

@ -9,8 +9,6 @@
#include <stddef.h>
#include <stdlib.h>
static bool can_multiply(size_t const, size_t const, size_t const);
// Allocate an MMDB_data_pool_s. It initially has space for size
// MMDB_entry_data_list_s structs.
MMDB_data_pool_s *data_pool_new(size_t const size) {
@ -43,7 +41,7 @@ MMDB_data_pool_s *data_pool_new(size_t const size) {
// the given max. max will typically be SIZE_MAX.
//
// We want to know if we'll wrap around.
static bool can_multiply(size_t const max, size_t const m, size_t const n) {
bool can_multiply(size_t const max, size_t const m, size_t const n) {
if (m == 0) {
return false;
}

View file

@ -44,6 +44,7 @@ typedef struct MMDB_data_pool_s {
MMDB_entry_data_list_s *blocks[DATA_POOL_NUM_BLOCKS];
} MMDB_data_pool_s;
bool can_multiply(size_t const, size_t const, size_t const);
MMDB_data_pool_s *data_pool_new(size_t const);
void data_pool_destroy(MMDB_data_pool_s *const);
MMDB_entry_data_list_s *data_pool_alloc(MMDB_data_pool_s *const);

View file

@ -23,6 +23,10 @@
#endif
#include <windows.h>
#include <ws2ipdef.h>
#ifndef SSIZE_MAX
#define SSIZE_MAX INTPTR_MAX
#endif
typedef ADDRESS_FAMILY sa_family_t;
#else
#include <arpa/inet.h>
#include <sys/mman.h>
@ -288,18 +292,29 @@ int MMDB_open(const char *const filename, uint32_t flags, MMDB_s *const mmdb) {
goto cleanup;
}
uint32_t search_tree_size =
mmdb->metadata.node_count * mmdb->full_record_byte_size;
mmdb->data_section =
mmdb->file_content + search_tree_size + MMDB_DATA_SECTION_SEPARATOR;
if (search_tree_size + MMDB_DATA_SECTION_SEPARATOR >
(uint32_t)mmdb->file_size) {
if (!can_multiply(SSIZE_MAX,
mmdb->metadata.node_count,
mmdb->full_record_byte_size)) {
status = MMDB_INVALID_METADATA_ERROR;
goto cleanup;
}
mmdb->data_section_size = (uint32_t)mmdb->file_size - search_tree_size -
MMDB_DATA_SECTION_SEPARATOR;
ssize_t search_tree_size = (ssize_t)mmdb->metadata.node_count *
(ssize_t)mmdb->full_record_byte_size;
mmdb->data_section =
mmdb->file_content + search_tree_size + MMDB_DATA_SECTION_SEPARATOR;
if (mmdb->file_size < MMDB_DATA_SECTION_SEPARATOR ||
search_tree_size > mmdb->file_size - MMDB_DATA_SECTION_SEPARATOR) {
status = MMDB_INVALID_METADATA_ERROR;
goto cleanup;
}
ssize_t data_section_size =
mmdb->file_size - search_tree_size - MMDB_DATA_SECTION_SEPARATOR;
if (data_section_size > UINT32_MAX || data_section_size <= 0) {
status = MMDB_INVALID_METADATA_ERROR;
goto cleanup;
}
mmdb->data_section_size = (uint32_t)data_section_size;
// Although it is likely not possible to construct a database with valid
// valid metadata, as parsed above, and a data_section_size less than 3,

@ -1 +1 @@
Subproject commit 56e31231e0329b202c978c676e4a897c857c7a1f
Subproject commit b53e4ef5257f80e881762b6143834d8aae29da1a

View file

@ -1,4 +1,4 @@
dist: bionic
dist: focal
branches:
only:
@ -24,6 +24,11 @@ addons:
- libtest-longstring-perl
- liblist-moreutils-perl
- libgd-dev
- time
- cmake
- libunwind-dev
- wget
- libbrotli1
cache:
directories:
@ -38,9 +43,13 @@ env:
- LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1
- LUA_INCLUDE_DIR=$LUAJIT_INC
- PCRE_VER=8.45
- PCRE2_VER=10.37
- PCRE_PREFIX=/opt/pcre
- PCRE2_PREFIX=/opt/pcre2
- PCRE_LIB=$PCRE_PREFIX/lib
- PCRE2_LIB=$PCRE2_PREFIX/lib
- PCRE_INC=$PCRE_PREFIX/include
- PCRE2_INC=$PCRE2_PREFIX/include
- OPENSSL_PREFIX=/opt/ssl
- OPENSSL_LIB=$OPENSSL_PREFIX/lib
- OPENSSL_INC=$OPENSSL_PREFIX/include
@ -50,9 +59,14 @@ env:
- LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH
- DRIZZLE_VER=2011.07.21
- TEST_NGINX_SLEEP=0.006
- MALLOC_PERTURB_=9
jobs:
- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d
- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f
#- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d
#- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d
- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f
- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y
- NGINX_VERSION=1.25.1 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 USE_PCRE2=Y
#- NGINX_VERSION=1.25.1 OPENSSL_VER=1.1.1w TEST_NGINX_USE_HTTP2=1
services:
- memcached
@ -60,16 +74,18 @@ services:
- mysql
before_install:
- sudo apt update
- sudo apt install --only-upgrade ca-certificates
- '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)'
- '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)'
- /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1)
- pyenv global 2.7
install:
- if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache http://openresty.org/download/drizzle7-$DRIZZLE_VER.tar.gz; fi
- if [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi
- if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi
- if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi
- if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi
- if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi
- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi
- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi
- wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz
- wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz
- git clone https://github.com/openresty/test-nginx.git
- git clone https://github.com/openresty/openresty.git ../openresty
- git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx
@ -91,21 +107,24 @@ install:
- git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core
- git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache
- git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql
- git clone https://github.com/spacewander/lua-resty-rsa.git ../lua-resty-rsa
- git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string
- git clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module
- git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2
before_script:
- mysql -uroot -e 'create database ngx_test; grant all on ngx_test.* to "ngx_test"@"%" identified by "ngx_test"; flush privileges;'
- mysql -uroot -e "create database ngx_test; CREATE USER 'ngx_test'@'%' IDENTIFIED WITH mysql_native_password BY 'ngx_test'; grant all on ngx_test.* to 'ngx_test'@'%'; flush privileges;"
script:
- export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:$PATH
- sudo tar -C / -xf curl-h3-x64-focal.tar.gz
- export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:/opt/curl-h3/bin:$PATH
- ngx-releng > check.txt || true
- lines=`wc -l check.txt | awk '{print $1}'`; if [ $lines -gt 5 ]; then cat check.txt; exit 1; fi
- sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT
- sudo iptables -I OUTPUT -p tcp --dst 127.0.0.2 --dport 12345 -j DROP
- sudo iptables -I OUTPUT -p udp --dst 127.0.0.2 --dport 12345 -j DROP
- sudo ip route add prohibit 0.0.0.1/32
- sudo sysctl -w kernel.pid_max=10000
- cd luajit2/
- make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2' > build.log 2>&1 || (cat build.log && exit 1)
- sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1)
@ -116,19 +135,10 @@ script:
- sudo make install-libdrizzle-1.0 > build.log 2>&1 || (cat build.log && exit 1)
- cd ../mockeagain/ && make CC=$CC -j$JOBS && cd ..
- cd lua-cjson/ && make -j$JOBS && sudo make install && cd ..
- tar zxf download-cache/pcre-$PCRE_VER.tar.gz
- cd pcre-$PCRE_VER/
- ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > build.log 2>&1 || (cat build.log && exit 1)
- make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1)
- sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1)
- cd ..
- tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz
- cd openssl-$OPENSSL_VER/
- patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch
- ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1)
- make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1)
- sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1)
- cd ..
- if [ "$USE_PCRE2" != "Y" ]; then tar zxf download-cache/pcre-$PCRE_VER.tar.gz; cd pcre-$PCRE_VER/; ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi
- if [ "$USE_PCRE2" = "Y" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi
- if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi
- if [ -n "$BORINGSSL" ]; then sudo mkdir -p /opt/ssl && sudo tar -C /opt/ssl -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi
- export NGX_BUILD_CC=$CC
- sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1)
- sh util/build-with-dd.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1)
@ -139,6 +149,8 @@ script:
- ldd `which nginx`|grep -E 'luajit|ssl|pcre'
- export LD_PRELOAD=$PWD/mockeagain/mockeagain.so
- export LD_LIBRARY_PATH=$PWD/mockeagain:$LD_LIBRARY_PATH
- export TEST_NGINX_HTTP3_CRT=$PWD/t/cert/http3/http3.crt
- export TEST_NGINX_HTTP3_KEY=$PWD/t/cert/http3/http3.key
- export TEST_NGINX_RESOLVER=8.8.4.4
- dig +short myip.opendns.com @resolver1.opendns.com || exit 0
- dig +short @$TEST_NGINX_RESOLVER openresty.org || exit 0

View file

@ -4,13 +4,11 @@ Name
ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers.
This module is a core component of [OpenResty](https://openresty.org). If you are using this module,
then you are essentially using OpenResty.
then you are essentially using OpenResty :)
*This module is not distributed with the Nginx source.* See
[the installation instructions](#installation).
This is a core component of OpenResty. If you are using this module, then you are essentially using OpenResty :)
Table of Contents
=================
@ -65,8 +63,8 @@ Version
=======
This document describes ngx_lua
[v0.10.19](https://github.com/openresty/lua-nginx-module/tags), which was released
on 3 Nov, 2020.
[v0.10.25](https://github.com/openresty/lua-nginx-module/tags), which was released
on 19 June 2023.
Videos
======
@ -309,6 +307,8 @@ Nginx Compatibility
The latest version of this module is compatible with the following versions of Nginx:
* 1.25.x (last tested: 1.25.1)
* 1.21.x (last tested: 1.21.4)
* 1.19.x (last tested: 1.19.3)
* 1.17.x (last tested: 1.17.8)
* 1.15.x (last tested: 1.15.8)
@ -964,7 +964,6 @@ TODO
* cosocket: implement LuaSocket's unconnected UDP API.
* cosocket: add support in the context of [init_by_lua*](#init_by_lua).
* cosocket: implement the `bind()` method for stream-typed cosockets.
* cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method.
* cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools.
* review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option
@ -1166,6 +1165,8 @@ Directives
* [lua_ssl_ciphers](#lua_ssl_ciphers)
* [lua_ssl_crl](#lua_ssl_crl)
* [lua_ssl_protocols](#lua_ssl_protocols)
* [lua_ssl_certificate](#lua_ssl_certificate)
* [lua_ssl_certificate_key](#lua_ssl_certificate_key)
* [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate)
* [lua_ssl_verify_depth](#lua_ssl_verify_depth)
* [lua_ssl_conf_command](#lua_ssl_conf_command)
@ -2721,6 +2722,8 @@ lua_need_request_body
**phase:** *depends on usage*
Due to the stream processing feature of HTTP/2 or HTTP/3, this configuration could potentially block the entire request. Therefore, this configuration is effective only when HTTP/2 or HTTP/3 requests send content-length header. For requests with versions lower than HTTP/2, this configuration can still be used without any problems.
Determines whether to force the request body data to be read before running rewrite/access/content_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code.
To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable,
@ -3321,24 +3324,63 @@ lua_ssl_protocols
**syntax:** *lua_ssl_protocols \[SSLv2\] \[SSLv3\] \[TLSv1\] [TLSv1.1] [TLSv1.2] [TLSv1.3]*
**default:** *lua_ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2*
**default:** *lua_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3*
**context:** *http, server, location*
Enables the specified protocols for requests to a SSL/TLS server in the [tcpsock:sslhandshake](#tcpsocksslhandshake) method.
The support for the `TLSv1.3` parameter requires version `v0.10.12` *and* OpenSSL 1.1.1.
From version v0.10.25, the default value change from `SSLV3 TLSv1 TLSv1.1 TLSv1.2` to `TLSv1 TLSv1.1 TLSv1.2 TLSv1.3`.
This directive was first introduced in the `v0.9.11` release.
[Back to TOC](#directives)
lua_ssl_certificate
-------------------
**syntax:** *lua_ssl_certificate &lt;file&gt;*
**default:** *none*
**context:** *http, server, location*
Specifies the file path to the SSL/TLS certificate in PEM format used for the [tcpsock:sslhandshake](#tcpsocksslhandshake) method.
This directive allows you to specify the SSL/TLS certificate that will be presented to server during the SSL/TLS handshake process.
This directive was first introduced in the `v0.10.26` release.
See also [lua_ssl_certificate_key](#lua_ssl_certificate_key) and [lua_ssl_verify_depth](#lua_ssl_verify_depth).
[Back to TOC](#directives)
lua_ssl_certificate_key
-----------------------
**syntax:** *lua_ssl_certificate_key &lt;file&gt;*
**default:** *none*
**context:** *http, server, location*
Specifies the file path to the private key associated with the SSL/TLS certificate used in the [tcpsock:sslhandshake](#tcpsocksslhandshake) method.
This directive allows you to specify the private key file corresponding to the SSL/TLS certificate specified by lua_ssl_certificate. The private key should be in PEM format and must match the certificate.
This directive was first introduced in the `v0.10.26` release.
See also [lua_ssl_certificate](#lua_ssl_certificate) and [lua_ssl_verify_depth](#lua_ssl_verify_depth).
[Back to TOC](#directives)
lua_ssl_trusted_certificate
---------------------------
**syntax:** *lua_ssl_trusted_certificate &lt;file&gt;*
**default:** *no*
**default:** *none*
**context:** *http, server, location*
@ -3363,7 +3405,7 @@ Sets the verification depth in the server certificates chain.
This directive was first introduced in the `v0.9.11` release.
See also [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate).
See also [lua_ssl_certificate](#lua_ssl_certificate), [lua_ssl_certificate_key](#lua_ssl_certificate_key) and [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate).
[Back to TOC](#directives)
@ -5384,6 +5426,8 @@ Reads the client request body synchronously without blocking the Nginx event loo
local args = ngx.req.get_post_args()
```
Due to the stream processing feature of HTTP/2 or HTTP/3, this api could potentially block the entire request. Therefore, this api is effective only when HTTP/2 or HTTP/3 requests send content-length header. For requests with versions lower than HTTP/2, this api can still be used without any problems.
If the request body is already read previously by turning on [lua_need_request_body](#lua_need_request_body) or by using other modules, then this function does not run and returns immediately.
If the request body has already been explicitly discarded, either by the [ngx.req.discard_body](#ngxreqdiscard_body) function or other modules, this function does not run and returns immediately.
@ -5423,12 +5467,14 @@ See also [ngx.req.read_body](#ngxreqread_body).
ngx.req.get_body_data
---------------------
**syntax:** *data = ngx.req.get_body_data()*
**syntax:** *data = ngx.req.get_body_data(max_bytes?)*
**context:** *rewrite_by_lua&#42;, access_by_lua&#42;, content_by_lua&#42;, log_by_lua&#42;*
Retrieves in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. Use the [ngx.req.get_post_args](#ngxreqget_post_args) function instead if a Lua table is required.
The optional `max_bytes` argument can be used when you don't need the entire body.
This function returns `nil` if
1. the request body has not been read,
@ -5597,6 +5643,8 @@ Returns a read-only cosocket object that wraps the downstream connection. Only [
In case of error, `nil` will be returned as well as a string describing the error.
Due to the streaming nature of HTTP2 and HTTP3, this API cannot be used when the downstream connection is HTTP2 and HTTP3.
The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [lua_need_request_body](#lua_need_request_body) directive, and do not mix this call with [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body).
If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading.
@ -9321,12 +9369,6 @@ Only the following ngx_lua APIs could be used in `function_name` function of the
* `ngx.decode_args`
* `ngx.quote_sql_str`
* `ngx.re.match`
* `ngx.re.find`
* `ngx.re.gmatch`
* `ngx.re.sub`
* `ngx.re.gsub`
* `ngx.crc32_short`
* `ngx.crc32_long`
* `ngx.hmac_sha1`
@ -9353,7 +9395,7 @@ The second argument `module_name` specifies the lua module name to execute in th
The third argument `func_name` specifies the function field in the module table as the second argument.
The type of `arg`s must be one of type below:
The type of `args` must be one of type below:
* boolean
* number

View file

@ -17,8 +17,8 @@ Production ready.
= Version =
This document describes ngx_lua
[https://github.com/openresty/lua-nginx-module/tags v0.10.19], which was released
on 3 Nov, 2020.
[https://github.com/openresty/lua-nginx-module/tags v0.10.25], which was released
on 19 June 2023.
= Videos =
@ -2845,11 +2845,43 @@ The support for the <code>TLSv1.3</code> parameter requires version <code>v0.10.
This directive was first introduced in the <code>v0.9.11</code> release.
== lua_ssl_certificate ==
'''syntax:''' ''lua_ssl_certificate <file>''
'''default:''' ''none''
'''context:''' ''http, server, location''
Specifies the file path to the SSL/TLS certificate in PEM format used for the [[#tcpsock:sslhandshake|tcpsock:sslhandshake]] method.
This directive allows you to specify the SSL/TLS certificate that will be presented to server during the SSL/TLS handshake process.
This directive was first introduced in the <code>v0.10.26</code> release.
See also [[#lua_ssl_certificate_key|lua_ssl_certificate_key]] and [[#lua_ssl_verify_depth|lua_ssl_verify_depth]].
== lua_ssl_certificate_key ==
'''syntax:''' ''lua_ssl_certificate_key <file>''
'''default:''' ''none''
'''context:''' ''http, server, location''
Specifies the file path to the private key associated with the SSL/TLS certificate used in the [[#tcpsock:sslhandshake|tcpsock:sslhandshake]] method.
This directive allows you to specify the private key file corresponding to the SSL/TLS certificate specified by lua_ssl_certificate. The private key should be in PEM format and must match the certificate.
This directive was first introduced in the <code>v0.10.26</code> release.
See also [[#lua_ssl_certificate|lua_ssl_certificate]] and [[#lua_ssl_verify_depth|lua_ssl_verify_depth]].
== lua_ssl_trusted_certificate ==
'''syntax:''' ''lua_ssl_trusted_certificate <file>''
'''default:''' ''no''
'''default:''' ''none''
'''context:''' ''http, server, location''
@ -2871,7 +2903,7 @@ Sets the verification depth in the server certificates chain.
This directive was first introduced in the <code>v0.9.11</code> release.
See also [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]].
See also [[#lua_ssl_certificate|lua_ssl_certificate]], [[#lua_ssl_certificate_key|lua_ssl_certificate_key]] and [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]].
== lua_ssl_conf_command ==
@ -4555,12 +4587,14 @@ See also [[#ngx.req.read_body|ngx.req.read_body]].
== ngx.req.get_body_data ==
'''syntax:''' ''data = ngx.req.get_body_data()''
'''syntax:''' ''data = ngx.req.get_body_data(max_bytes?)''
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, log_by_lua*''
Retrieves in-memory request body data. It returns a Lua string rather than a Lua table holding all the parsed query arguments. Use the [[#ngx.req.get_post_args|ngx.req.get_post_args]] function instead if a Lua table is required.
The optional <code>max_bytes</code> function argument can be used when you don't need the entire body.
This function returns <code>nil</code> if
# the request body has not been read,
@ -4707,6 +4741,8 @@ Returns a read-only cosocket object that wraps the downstream connection. Only [
In case of error, <code>nil</code> will be returned as well as a string describing the error.
Due to the streaming nature of HTTP2 and HTTP3, this API cannot be used when the downstream connection is HTTP2 and HTTP3.
The socket object returned by this method is usually used to read the current request's body in a streaming fashion. Do not turn on the [[#lua_need_request_body|lua_need_request_body]] directive, and do not mix this call with [[#ngx.req.read_body|ngx.req.read_body]] and [[#ngx.req.discard_body|ngx.req.discard_body]].
If any request body data has been pre-read into the Nginx core request header buffer, the resulting cosocket object will take care of this to avoid potential data loss resulting from such pre-reading.

View file

@ -19,7 +19,7 @@
/* Public API for other Nginx modules */
#define ngx_http_lua_version 10025
#define ngx_http_lua_version 10026
typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t;

View file

@ -137,6 +137,26 @@ ngx_http_lua_access_handler(ngx_http_request_t *r)
}
if (llcf->force_read_body && !ctx->read_body_done) {
#if (NGX_HTTP_V2)
if (r->main->stream && r->headers_in.content_length_n < 0) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"disable lua_need_request_body, since "
"http2 read_body may break http2 stream process");
goto done;
}
#endif
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.content_length_n < 0)
{
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"disable lua_need_request_body, since "
"http2 read_body may break http2 stream process");
goto done;
}
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;
@ -154,6 +174,12 @@ ngx_http_lua_access_handler(ngx_http_request_t *r)
}
}
#if defined(NGX_HTTP_V3) || defined(NGX_HTTP_V2)
done:
#endif
dd("calling access handler");
return llcf->access_handler(r);
}

View file

@ -91,7 +91,7 @@
* | Int | At which line this function is defined
* | [linedefined] |
* ---------------------
* | Int | At while line this function definition ended
* | Int | At which line this function definition ended
* | [lastlinedefined] |
* ---------------------
* | Char | Number of upvalues referenced by this function
@ -128,7 +128,7 @@
* | Vector | Debug lineinfo vector
* | [lineinfo] | Empty vector here if debug info is stripped
* ---------------------
* | Int | Number of local variable in this function
* | Int | Number of local variables in this function
* | [sizelocvars] | 0 if debug info is stripped
* ---------------------
* | String | ------------------------------------

View file

@ -55,11 +55,17 @@ typedef struct {
#if (NGX_PCRE)
#include <pcre.h>
# if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21)
# if (NGX_PCRE2)
# define LUA_HAVE_PCRE_JIT 1
# else
# define LUA_HAVE_PCRE_JIT 0
#include <pcre.h>
# if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21)
# define LUA_HAVE_PCRE_JIT 1
# else
# define LUA_HAVE_PCRE_JIT 0
# endif
# endif
#endif
@ -221,9 +227,14 @@ struct ngx_http_lua_main_conf_s {
ngx_int_t regex_cache_entries;
ngx_int_t regex_cache_max_entries;
ngx_int_t regex_match_limit;
# if (LUA_HAVE_PCRE_JIT)
#endif
#if (LUA_HAVE_PCRE_JIT)
#if (NGX_PCRE2)
pcre2_jit_stack *jit_stack;
#else
pcre_jit_stack *jit_stack;
# endif
#endif
#endif
ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */
@ -360,6 +371,8 @@ union ngx_http_lua_srv_conf_u {
typedef struct {
#if (NGX_HTTP_SSL)
ngx_ssl_t *ssl; /* shared by SSL cosockets */
ngx_array_t *ssl_certificates;
ngx_array_t *ssl_certificate_keys;
ngx_uint_t ssl_protocols;
ngx_str_t ssl_ciphers;
ngx_uint_t ssl_verify_depth;

View file

@ -196,6 +196,26 @@ ngx_http_lua_content_handler(ngx_http_request_t *r)
}
if (llcf->force_read_body && !ctx->read_body_done) {
#if (NGX_HTTP_V2)
if (r->main->stream && r->headers_in.content_length_n < 0) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"disable lua_need_request_body, since "
"http2 read_body may break http2 stream process");
goto done;
}
#endif
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.content_length_n < 0)
{
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"disable lua_need_request_body, since "
"http2 read_body may break http2 stream process");
goto done;
}
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;
@ -214,6 +234,12 @@ ngx_http_lua_content_handler(ngx_http_request_t *r)
}
}
#if defined(NGX_HTTP_V3) || defined(NGX_HTTP_V2)
done:
#endif
dd("setting entered");
ctx->entered_content_phase = 1;

View file

@ -280,6 +280,9 @@ ngx_http_lua_ngx_redirect(lua_State *L)
h->value.len = len;
h->value.data = uri;
#if defined(nginx_version) && nginx_version >= 1023000
h->next = NULL;
#endif
ngx_str_set(&h->key, "Location");
r->headers_out.status = rc;

View file

@ -782,6 +782,11 @@ ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max,
{
int count;
ngx_list_part_t *part;
#if (NGX_HTTP_V3)
int has_host = 0;
ngx_uint_t i;
ngx_table_elt_t *header;
#endif
if (r->connection->fd == (ngx_socket_t) -1) {
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
@ -794,11 +799,54 @@ ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max,
}
part = &r->headers_in.headers.part;
#if (NGX_HTTP_V3)
count = 0;
header = part->elts;
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.server.data != NULL)
{
has_host = 1;
count++;
}
if (has_host == 1) {
for (i = 0; /* void */; i++) {
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
part = part->next;
header = part->elts;
i = 0;
}
if (header[i].key.len == 4
&& ngx_strncasecmp(header[i].key.data,
(u_char *) "host", 4) == 0)
{
continue;
}
count++;
}
} else {
count = part->nelts;
while (part->next != NULL) {
part = part->next;
count += part->nelts;
}
}
#else
count = part->nelts;
while (part->next != NULL) {
part = part->next;
count += part->nelts;
}
#endif
if (max > 0 && count > max) {
*truncated = 1;
@ -821,12 +869,29 @@ ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r,
ngx_uint_t i;
ngx_list_part_t *part;
ngx_table_elt_t *header;
#if (NGX_HTTP_V3)
int has_host = 0;
#endif
if (count <= 0) {
return NGX_OK;
}
n = 0;
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.server.data != NULL)
{
out[n].key.data = (u_char *) "host";
out[n].key.len = sizeof("host") - 1;
out[n].value.len = r->headers_in.server.len;
out[n].value.data = r->headers_in.server.data;
has_host = 1;
++n;
}
#endif
part = &r->headers_in.headers.part;
header = part->elts;
@ -842,6 +907,14 @@ ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r,
i = 0;
}
#if (NGX_HTTP_V3)
if (has_host == 1 && header[i].key.len == 4
&& ngx_strncasecmp(header[i].key.data, (u_char *) "host", 4) == 0)
{
continue;
}
#endif
if (raw) {
out[n].key.data = header[i].key.data;
out[n].key.len = (int) header[i].key.len;

View file

@ -280,6 +280,9 @@ new_header:
h->key = hv->key;
h->value = *value;
#if defined(nginx_version) && nginx_version >= 1023000
h->next = NULL;
#endif
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
if (h->lowcase_key == NULL) {
@ -588,19 +591,21 @@ ngx_http_set_builtin_multi_header(ngx_http_request_t *r,
{
#if defined(nginx_version) && nginx_version >= 1023000
ngx_table_elt_t **headers, **ph, *h;
int nelts;
headers = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset);
if (!hv->no_override && *headers != NULL) {
nelts = 0;
#if defined(DDEBUG) && (DDEBUG)
int nelts = 0;
for (h = *headers; h; h = h->next) {
nelts++;
}
*headers = NULL;
dd("clear multi-value headers: %d", nelts);
#endif
*headers = NULL;
}
if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) {

View file

@ -229,6 +229,9 @@ new_header:
h->key = hv->key;
h->value = *value;
#if defined(nginx_version) && nginx_version >= 1023000
h->next = NULL;
#endif
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
if (h->lowcase_key == NULL) {

View file

@ -48,6 +48,8 @@ static char *ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent,
static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf);
static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data);
#if (NGX_HTTP_SSL)
static ngx_int_t ngx_http_lua_merge_ssl(ngx_conf_t *cf,
ngx_http_lua_loc_conf_t *conf, ngx_http_lua_loc_conf_t *prev);
static ngx_int_t ngx_http_lua_set_ssl(ngx_conf_t *cf,
ngx_http_lua_loc_conf_t *llcf);
#if (nginx_version >= 1019004)
@ -57,6 +59,9 @@ static char *ngx_http_lua_ssl_conf_command_check(ngx_conf_t *cf, void *post,
#endif
static char *ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#if (NGX_PCRE2)
extern void ngx_http_lua_regex_cleanup(void *data);
#endif
static ngx_conf_post_t ngx_http_lua_lowat_post =
@ -648,6 +653,20 @@ static ngx_command_t ngx_http_lua_cmds[] = {
offsetof(ngx_http_lua_loc_conf_t, ssl_verify_depth),
NULL },
{ ngx_string("lua_ssl_certificate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_array_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_lua_loc_conf_t, ssl_certificates),
NULL },
{ ngx_string("lua_ssl_certificate_key"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_array_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_lua_loc_conf_t, ssl_certificate_keys),
NULL },
{ ngx_string("lua_ssl_trusted_certificate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
@ -839,6 +858,17 @@ ngx_http_lua_init(ngx_conf_t *cf)
cln->data = lmcf;
cln->handler = ngx_http_lua_sema_mm_cleanup;
#if (NGX_PCRE2)
/* add the cleanup of pcre2 regex */
cln = ngx_pool_cleanup_add(cf->pool, 0);
if (cln == NULL) {
return NGX_ERROR;
}
cln->data = lmcf;
cln->handler = ngx_http_lua_regex_cleanup;
#endif
#ifdef HAVE_NGX_LUA_PIPE
ngx_http_lua_pipe_init();
#endif
@ -1148,15 +1178,15 @@ ngx_http_lua_create_srv_conf(ngx_conf_t *cf)
* lscf->srv.ssl_cert_chunkname = NULL;
* lscf->srv.ssl_cert_src_key = NULL;
*
* lscf->srv.ssl_session_store_handler = NULL;
* lscf->srv.ssl_session_store_src = { 0, NULL };
* lscf->srv.ssl_session_store_chunkname = NULL;
* lscf->srv.ssl_session_store_src_key = NULL;
* lscf->srv.ssl_sess_store_handler = NULL;
* lscf->srv.ssl_sess_store_src = { 0, NULL };
* lscf->srv.ssl_sess_store_chunkname = NULL;
* lscf->srv.ssl_sess_store_src_key = NULL;
*
* lscf->srv.ssl_session_fetch_handler = NULL;
* lscf->srv.ssl_session_fetch_src = { 0, NULL };
* lscf->srv.ssl_session_fetch_chunkname = NULL;
* lscf->srv.ssl_session_fetch_src_key = NULL;
* lscf->srv.ssl_sess_fetch_handler = NULL;
* lscf->srv.ssl_sess_fetch_src = { 0, NULL };
* lscf->srv.ssl_sess_fetch_chunkname = NULL;
* lscf->srv.ssl_sess_fetch_src_key = NULL;
*
* lscf->balancer.handler = NULL;
* lscf->balancer.src = { 0, NULL };
@ -1399,6 +1429,8 @@ ngx_http_lua_create_loc_conf(ngx_conf_t *cf)
#if (NGX_HTTP_SSL)
conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
conf->ssl_certificates = NGX_CONF_UNSET_PTR;
conf->ssl_certificate_keys = NGX_CONF_UNSET_PTR;
#if (nginx_version >= 1019004)
conf->ssl_conf_commands = NGX_CONF_UNSET_PTR;
#endif
@ -1464,16 +1496,24 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_HTTP_SSL)
if (ngx_http_lua_merge_ssl(cf, conf, prev) != NGX_OK) {
return NGX_CONF_ERROR;
}
ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
(NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3
(NGX_CONF_BITMASK_SET
|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
|NGX_SSL_TLSv1_2));
|NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
"DEFAULT");
ngx_conf_merge_uint_value(conf->ssl_verify_depth,
prev->ssl_verify_depth, 1);
ngx_conf_merge_ptr_value(conf->ssl_certificates,
prev->ssl_certificates, NULL);
ngx_conf_merge_ptr_value(conf->ssl_certificate_keys,
prev->ssl_certificate_keys, NULL);
ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
prev->ssl_trusted_certificate, "");
ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
@ -1527,17 +1567,77 @@ ngx_http_lua_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
#if (NGX_HTTP_SSL)
static ngx_int_t
ngx_http_lua_merge_ssl(ngx_conf_t *cf,
ngx_http_lua_loc_conf_t *conf, ngx_http_lua_loc_conf_t *prev)
{
ngx_uint_t preserve;
if (conf->ssl_protocols == 0
&& conf->ssl_ciphers.data == NULL
&& conf->ssl_verify_depth == NGX_CONF_UNSET_UINT
&& conf->ssl_certificates == NGX_CONF_UNSET_PTR
&& conf->ssl_certificate_keys == NGX_CONF_UNSET_PTR
&& conf->ssl_trusted_certificate.data == NULL
&& conf->ssl_crl.data == NULL
#if (nginx_version >= 1019004)
&& conf->ssl_conf_commands == NGX_CONF_UNSET_PTR
#endif
)
{
if (prev->ssl) {
conf->ssl = prev->ssl;
return NGX_OK;
}
preserve = 1;
} else {
preserve = 0;
}
conf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
if (conf->ssl == NULL) {
return NGX_ERROR;
}
conf->ssl->log = cf->log;
/*
* special handling to preserve conf->ssl_* in the "http" section
* to inherit it to all servers
*/
if (preserve) {
prev->ssl = conf->ssl;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf)
{
ngx_pool_cleanup_t *cln;
llcf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
if (llcf->ssl == NULL) {
return NGX_ERROR;
if (llcf->ssl->ctx) {
return NGX_OK;
}
llcf->ssl->log = cf->log;
if (llcf->ssl_certificates) {
if (llcf->ssl_certificate_keys == NULL
|| llcf->ssl_certificate_keys->nelts
< llcf->ssl_certificates->nelts)
{
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no \"lua_ssl_certificate_key\" is defined "
"for certificate \"%V\"",
((ngx_str_t *) llcf->ssl_certificates->elts)
+ llcf->ssl_certificates->nelts - 1);
return NGX_ERROR;
}
}
if (ngx_ssl_create(llcf->ssl, llcf->ssl_protocols, NULL) != NGX_OK) {
return NGX_ERROR;
@ -1562,6 +1662,16 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf)
return NGX_ERROR;
}
if (llcf->ssl_certificates
&& ngx_ssl_certificates(cf, llcf->ssl,
llcf->ssl_certificates,
llcf->ssl_certificate_keys,
NULL)
!= NGX_OK)
{
return NGX_ERROR;
}
if (llcf->ssl_trusted_certificate.len
&& ngx_ssl_trusted_certificate(cf, llcf->ssl,
&llcf->ssl_trusted_certificate,

View file

@ -18,15 +18,61 @@
static ngx_pool_t *ngx_http_lua_pcre_pool = NULL;
#if (NGX_PCRE2)
static ngx_uint_t ngx_regex_direct_alloc;
#else
static void *(*old_pcre_malloc)(size_t);
static void (*old_pcre_free)(void *ptr);
#endif
/* XXX: work-around to nginx regex subsystem, must init a memory pool
* to use PCRE functions. As PCRE still has memory-leaking problems,
* and nginx overwrote pcre_malloc/free hooks with its own static
* functions, so nobody else can reuse nginx regex subsystem... */
static void *
#if (NGX_PCRE2)
void *
ngx_http_lua_pcre_malloc(size_t size, void *data)
{
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
if (ngx_http_lua_pcre_pool) {
return ngx_palloc(ngx_http_lua_pcre_pool, size);
}
if (ngx_regex_direct_alloc) {
return ngx_alloc(size, ngx_cycle->log);
}
fprintf(stderr, "error: lua pcre malloc failed due to empty pcre pool");
return NULL;
}
void
ngx_http_lua_pcre_free(void *ptr, void *data)
{
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
if (ngx_http_lua_pcre_pool) {
ngx_pfree(ngx_http_lua_pcre_pool, ptr);
return;
}
if (ngx_regex_direct_alloc) {
ngx_free(ptr);
return;
}
fprintf(stderr, "error: lua pcre free failed due to empty pcre pool");
}
#else
void *
ngx_http_lua_pcre_malloc(size_t size)
{
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
@ -54,6 +100,41 @@ ngx_http_lua_pcre_free(void *ptr)
fprintf(stderr, "error: lua pcre free failed due to empty pcre pool");
}
#endif
#if (NGX_PCRE2)
ngx_pool_t *
ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool)
{
ngx_pool_t *old_pool;
dd("lua pcre pool was %p", ngx_http_lua_pcre_pool);
ngx_regex_direct_alloc = (pool == NULL) ? 1 : 0;
old_pool = ngx_http_lua_pcre_pool;
ngx_http_lua_pcre_pool = pool;
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
return old_pool;
}
void
ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool)
{
dd("lua pcre pool was %p", ngx_http_lua_pcre_pool);
ngx_http_lua_pcre_pool = old_pool;
ngx_regex_direct_alloc = 0;
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
}
#else
ngx_pool_t *
ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool)
@ -101,6 +182,7 @@ ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool)
}
}
#endif
#endif /* NGX_PCRE */
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */

View file

@ -13,8 +13,15 @@
#if (NGX_PCRE)
ngx_pool_t *ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool);
void ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool);
#if NGX_PCRE2
void *ngx_http_lua_pcre_malloc(size_t size, void *data);
void ngx_http_lua_pcre_free(void *ptr, void *data);
#endif
#endif

View file

@ -9,7 +9,6 @@
#endif
#include "ddebug.h"
#if (NGX_PCRE)
#include "ngx_http_lua_pcrefix.h"
@ -17,13 +16,24 @@
#include "ngx_http_lua_util.h"
#if (PCRE_MAJOR >= 6)
#if (PCRE_MAJOR >= 6 || NGX_PCRE2)
# define LUA_HAVE_PCRE_DFA 1
#else
# define LUA_HAVE_PCRE_DFA 0
#endif
#if (NGX_PCRE2)
static pcre2_compile_context *ngx_regex_compile_context;
static pcre2_match_context *ngx_regex_match_context;
static pcre2_match_data *ngx_regex_match_data;
static ngx_uint_t ngx_regex_match_data_size = 0;
#define PCRE2_VERSION_SIZE 64
static char ngx_pcre2_version[PCRE2_VERSION_SIZE];
#endif
#define NGX_LUA_RE_MODE_DFA (1<<1)
#define NGX_LUA_RE_MODE_JIT (1<<2)
#define NGX_LUA_RE_NO_UTF8_CHECK (1<<4)
@ -42,8 +52,17 @@ typedef struct {
int ncaptures;
int *captures;
#if (NGX_PCRE2)
pcre2_code *regex;
/*
* pcre2 doesn't use pcre_extra any more,
* just for keeping same memory layout in the lua ffi cdef
*/
void *regex_sd;
#else
pcre *regex;
pcre_extra *regex_sd;
#endif
ngx_http_lua_complex_value_t *replace;
@ -57,7 +76,11 @@ typedef struct {
ngx_pool_t *pool;
ngx_int_t options;
#if (NGX_PCRE2)
pcre2_code *regex;
#else
pcre *regex;
#endif
int captures;
ngx_str_t err;
} ngx_http_lua_regex_compile_t;
@ -65,8 +88,12 @@ typedef struct {
typedef struct {
ngx_http_request_t *request;
#if (NGX_PCRE2)
pcre2_code *regex;
#else
pcre *regex;
pcre_extra *regex_sd;
#endif
int ncaptures;
int *captures;
int captures_len;
@ -74,8 +101,6 @@ typedef struct {
} ngx_http_lua_regex_ctx_t;
static void ngx_http_lua_regex_free_study_data(ngx_pool_t *pool,
pcre_extra *sd);
static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc);
@ -91,22 +116,156 @@ static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc);
static void
ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd)
ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, ngx_http_lua_regex_t *re)
{
ngx_pool_t *old_pool;
ngx_pool_t *old_pool;
old_pool = ngx_http_lua_pcre_malloc_init(pool);
#if (NGX_PCRE2)
if (re && re->regex) {
old_pool = ngx_http_lua_pcre_malloc_init(pool);
#if LUA_HAVE_PCRE_JIT
pcre_free_study(sd);
pcre2_code_free(re->regex);
ngx_http_lua_pcre_malloc_done(old_pool);
re->regex = NULL;
}
#else
pcre_free(sd);
if (re && re->regex_sd) {
old_pool = ngx_http_lua_pcre_malloc_init(pool);
#if LUA_HAVE_PCRE_JIT
pcre_free_study(re->regex_sd);
#else
pcre_free(re->regex_sd);
#endif
ngx_http_lua_pcre_malloc_done(old_pool);
ngx_http_lua_pcre_malloc_done(old_pool);
re->regex_sd = NULL;
}
#endif
}
#if (NGX_PCRE2)
static ngx_int_t
ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc)
{
int n, errcode;
char *p;
size_t erroff;
u_char errstr[128];
pcre2_code *re;
ngx_pool_t *old_pool;
pcre2_general_context *gctx;
pcre2_compile_context *cctx;
ngx_http_lua_main_conf_t *lmcf;
if (ngx_regex_compile_context == NULL) {
/*
* Allocate a compile context if not yet allocated. This uses
* direct allocations from heap, so the result can be cached
* even at runtime.
*/
old_pool = ngx_http_lua_pcre_malloc_init(NULL);
gctx = pcre2_general_context_create(ngx_http_lua_pcre_malloc,
ngx_http_lua_pcre_free,
NULL);
if (gctx == NULL) {
ngx_http_lua_pcre_malloc_done(old_pool);
goto nomem;
}
cctx = pcre2_compile_context_create(gctx);
if (cctx == NULL) {
pcre2_general_context_free(gctx);
ngx_http_lua_pcre_malloc_done(old_pool);
goto nomem;
}
ngx_regex_compile_context = cctx;
ngx_regex_match_context = pcre2_match_context_create(gctx);
if (ngx_regex_match_context == NULL) {
pcre2_general_context_free(gctx);
ngx_http_lua_pcre_malloc_done(old_pool);
goto nomem;
}
lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
ngx_http_lua_module);
if (lmcf && lmcf->regex_match_limit > 0) {
pcre2_set_match_limit(ngx_regex_match_context,
lmcf->regex_match_limit);
}
pcre2_general_context_free(gctx);
ngx_http_lua_pcre_malloc_done(old_pool);
}
old_pool = ngx_http_lua_pcre_malloc_init(rc->pool);
re = pcre2_compile(rc->pattern.data,
rc->pattern.len, rc->options,
&errcode, &erroff, ngx_regex_compile_context);
ngx_http_lua_pcre_malloc_done(old_pool);
if (re == NULL) {
pcre2_get_error_message(errcode, errstr, 128);
if ((size_t) erroff == rc->pattern.len) {
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
"pcre2_compile() failed: %s in \"%V\"",
errstr, &rc->pattern)
- rc->err.data;
} else {
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
"pcre2_compile() failed: %s in "
"\"%V\" at \"%s\"", errstr, &rc->pattern,
rc->pattern.data + erroff)
- rc->err.data;
}
return NGX_ERROR;
}
rc->regex = re;
n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures);
if (n < 0) {
p = "pcre2_pattern_info(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
goto failed;
}
#if (NGX_DEBUG)
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre2_compile: pattern[%V], options 0x%08Xd, ncaptures %d",
&rc->pattern, rc->options, rc->captures);
#endif
return NGX_OK;
failed:
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
- rc->err.data;
return NGX_ERROR;
nomem:
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
"regex \"%V\" compilation failed: no memory",
&rc->pattern)
- rc->err.data;
return NGX_ERROR;
}
#else
static ngx_int_t
ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc)
{
@ -159,13 +318,14 @@ failed:
- rc->err.data;
return NGX_OK;
}
#endif
ngx_int_t
ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr,
size_t *errstr_size)
{
#if LUA_HAVE_PCRE_JIT
#if (LUA_HAVE_PCRE_JIT)
ngx_http_lua_main_conf_t *lmcf;
ngx_pool_t *pool, *old_pool;
@ -186,15 +346,24 @@ ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr,
if (lmcf->jit_stack) {
old_pool = ngx_http_lua_pcre_malloc_init(pool);
#if (NGX_PCRE2)
pcre2_jit_stack_free(lmcf->jit_stack);
#else
pcre_jit_stack_free(lmcf->jit_stack);
#endif
ngx_http_lua_pcre_malloc_done(old_pool);
}
old_pool = ngx_http_lua_pcre_malloc_init(pool);
#if (NGX_PCRE2)
lmcf->jit_stack = pcre2_jit_stack_create(NGX_LUA_RE_MIN_JIT_STACK_SIZE,
size, NULL);
#else
lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE,
size);
#endif
ngx_http_lua_pcre_malloc_done(old_pool);
@ -214,10 +383,150 @@ ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr,
- errstr;
return NGX_ERROR;
#endif /* LUA_HAVE_PCRE_JIT */
#endif
}
#if (NGX_PCRE2)
static void
ngx_http_lua_regex_jit_compile(ngx_http_lua_regex_t *re, int flags,
ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf,
ngx_http_lua_regex_compile_t *re_comp)
{
ngx_int_t ret;
ngx_pool_t *old_pool;
if (flags & NGX_LUA_RE_MODE_JIT) {
old_pool = ngx_http_lua_pcre_malloc_init(pool);
ret = pcre2_jit_compile(re_comp->regex, PCRE2_JIT_COMPLETE);
if (ret != 0) {
ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0,
"pcre2_jit_compile() failed: %d in \"%V\", "
"ignored",
ret, &re_comp->pattern);
#if (NGX_DEBUG)
} else {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre2 JIT compiled successfully");
# endif /* !(NGX_DEBUG) */
}
ngx_http_lua_pcre_malloc_done(old_pool);
}
if (lmcf && lmcf->jit_stack) {
pcre2_jit_stack_assign(ngx_regex_match_context, NULL,
lmcf->jit_stack);
}
return;
}
#else
static void
ngx_http_lua_regex_jit_compile(ngx_http_lua_regex_t *re, int flags,
ngx_pool_t *pool, ngx_http_lua_main_conf_t *lmcf,
ngx_http_lua_regex_compile_t *re_comp)
{
const char *msg;
pcre_extra *sd = NULL;
ngx_pool_t *old_pool;
#if (LUA_HAVE_PCRE_JIT)
if (flags & NGX_LUA_RE_MODE_JIT) {
old_pool = ngx_http_lua_pcre_malloc_init(pool);
sd = pcre_study(re_comp->regex, PCRE_STUDY_JIT_COMPILE, &msg);
ngx_http_lua_pcre_malloc_done(old_pool);
# if (NGX_DEBUG)
if (msg != NULL) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre study failed with PCRE_STUDY_JIT_COMPILE: "
"%s (%p)", msg, sd);
}
if (sd != NULL) {
int jitted;
old_pool = ngx_http_lua_pcre_malloc_init(pool);
pcre_fullinfo(re_comp->regex, sd, PCRE_INFO_JIT, &jitted);
ngx_http_lua_pcre_malloc_done(old_pool);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre JIT compiling result: %d", jitted);
}
# endif /* !(NGX_DEBUG) */
} else {
old_pool = ngx_http_lua_pcre_malloc_init(pool);
sd = pcre_study(re_comp->regex, 0, &msg);
ngx_http_lua_pcre_malloc_done(old_pool);
}
if (sd && lmcf && lmcf->jit_stack) {
pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack);
}
if (sd
&& lmcf && lmcf->regex_match_limit > 0
&& !(flags & NGX_LUA_RE_MODE_DFA))
{
sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
sd->match_limit = lmcf->regex_match_limit;
}
#endif /* LUA_HAVE_PCRE_JIT */
re->regex_sd = sd;
}
#endif
#if (NGX_PCRE2)
void
ngx_http_lua_regex_cleanup(void *data)
{
ngx_pool_t *old_pool;
ngx_http_lua_main_conf_t *lmcf;
lmcf = data;
if (ngx_regex_compile_context) {
old_pool = ngx_http_lua_pcre_malloc_init(NULL);
pcre2_compile_context_free(ngx_regex_compile_context);
ngx_regex_compile_context = NULL;
ngx_http_lua_pcre_malloc_done(old_pool);
}
if (lmcf && lmcf->jit_stack) {
old_pool = ngx_http_lua_pcre_malloc_init(NULL);
pcre2_jit_stack_free(lmcf->jit_stack);
lmcf->jit_stack = NULL;
ngx_http_lua_pcre_malloc_done(old_pool);
}
if (ngx_regex_match_data) {
old_pool = ngx_http_lua_pcre_malloc_init(NULL);
pcre2_match_data_free(ngx_regex_match_data);
ngx_regex_match_data = NULL;
ngx_regex_match_data_size = 0;
ngx_http_lua_pcre_malloc_done(old_pool);
}
}
#endif
ngx_http_lua_regex_t *
ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
int flags, int pcre_opts, u_char *errstr,
@ -228,8 +537,7 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
ngx_int_t rc;
const char *msg;
ngx_pool_t *pool, *old_pool;
pcre_extra *sd = NULL;
ngx_http_lua_regex_t *re;
ngx_http_lua_regex_t *re = NULL;
ngx_http_lua_main_conf_t *lmcf;
ngx_http_lua_regex_compile_t re_comp;
@ -251,6 +559,8 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
}
re->pool = pool;
re->regex = NULL;
re->regex_sd = NULL;
re_comp.options = pcre_opts;
re_comp.pattern.data = (u_char *) pat;
@ -274,54 +584,7 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
ngx_http_lua_assert(lmcf != NULL);
#if (LUA_HAVE_PCRE_JIT)
if (flags & NGX_LUA_RE_MODE_JIT) {
old_pool = ngx_http_lua_pcre_malloc_init(pool);
sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg);
ngx_http_lua_pcre_malloc_done(old_pool);
# if (NGX_DEBUG)
if (msg != NULL) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre study failed with PCRE_STUDY_JIT_COMPILE: "
"%s (%p)", msg, sd);
}
if (sd != NULL) {
int jitted;
old_pool = ngx_http_lua_pcre_malloc_init(pool);
pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted);
ngx_http_lua_pcre_malloc_done(old_pool);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre JIT compiling result: %d", jitted);
}
# endif /* !(NGX_DEBUG) */
} else {
old_pool = ngx_http_lua_pcre_malloc_init(pool);
sd = pcre_study(re_comp.regex, 0, &msg);
ngx_http_lua_pcre_malloc_done(old_pool);
}
if (sd && lmcf->jit_stack) {
pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack);
}
#endif /* LUA_HAVE_PCRE_JIT */
if (sd
&& lmcf && lmcf->regex_match_limit > 0
&& !(flags & NGX_LUA_RE_MODE_DFA))
{
sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
sd->match_limit = lmcf->regex_match_limit;
}
ngx_http_lua_regex_jit_compile(re, flags, pool, lmcf, &re_comp);
if (flags & NGX_LUA_RE_MODE_DFA) {
ovecsize = 2;
@ -339,6 +602,31 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
goto error;
}
#if (NGX_PCRE2)
if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMECOUNT,
&re->name_count) < 0)
{
msg = "cannot acquire named subpattern count";
goto error;
}
if (re->name_count > 0) {
if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMEENTRYSIZE,
&re->name_entry_size) != 0)
{
msg = "cannot acquire named subpattern entry size";
goto error;
}
if (pcre2_pattern_info(re_comp.regex, PCRE2_INFO_NAMETABLE,
&re->name_table) != 0)
{
msg = "cannot acquire named subpattern table";
goto error;
}
}
#else
if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT,
&re->name_count) != 0)
{
@ -361,9 +649,9 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
goto error;
}
}
#endif
re->regex = re_comp.regex;
re->regex_sd = sd;
re->ncaptures = re_comp.captures;
re->captures = cap;
re->replace = NULL;
@ -379,9 +667,7 @@ error:
p = ngx_snprintf(errstr, errstr_size - 1, "%s", msg);
*p = '\0';
if (sd) {
ngx_http_lua_regex_free_study_data(pool, sd);
}
ngx_http_lua_regex_free_study_data(pool, re);
if (pool) {
ngx_destroy_pool(pool);
@ -391,6 +677,103 @@ error:
}
#if (NGX_PCRE2)
int
ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
const u_char *s, size_t len, int pos)
{
int rc, exec_opts = 0;
size_t *ov;
ngx_uint_t ovecsize, n, i;
ngx_pool_t *old_pool;
if (flags & NGX_LUA_RE_MODE_DFA) {
ovecsize = 2;
re->ncaptures = 0;
} else {
ovecsize = (re->ncaptures + 1) * 3;
}
old_pool = ngx_http_lua_pcre_malloc_init(NULL);
if (ngx_regex_match_data == NULL
|| ovecsize > ngx_regex_match_data_size)
{
/*
* Allocate a match data if not yet allocated or smaller than
* needed.
*/
if (ngx_regex_match_data) {
pcre2_match_data_free(ngx_regex_match_data);
}
ngx_regex_match_data_size = ovecsize;
ngx_regex_match_data = pcre2_match_data_create(ovecsize / 3, NULL);
if (ngx_regex_match_data == NULL) {
rc = PCRE2_ERROR_NOMEMORY;
goto failed;
}
}
if (flags & NGX_LUA_RE_NO_UTF8_CHECK) {
exec_opts = PCRE2_NO_UTF_CHECK;
} else {
exec_opts = 0;
}
if (flags & NGX_LUA_RE_MODE_DFA) {
int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT];
rc = pcre2_dfa_match(re->regex, s, len, pos, exec_opts,
ngx_regex_match_data, ngx_regex_match_context,
ws, sizeof(ws) / sizeof(ws[0]));
} else {
rc = pcre2_match(re->regex, s, len, pos, exec_opts,
ngx_regex_match_data, ngx_regex_match_context);
}
if (rc < 0) {
#if (NGX_DEBUG)
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre2_match failed: flags 0x%05Xd, options 0x%08Xd, "
"rc %d, ovecsize %ui", flags, exec_opts, rc, ovecsize);
#endif
goto failed;
}
n = pcre2_get_ovector_count(ngx_regex_match_data);
ov = pcre2_get_ovector_pointer(ngx_regex_match_data);
#if (NGX_DEBUG)
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"pcre2_match: flags 0x%05Xd, options 0x%08Xd, rc %d, "
"n %ui, ovecsize %ui", flags, exec_opts, rc, n, ovecsize);
#endif
if (!(flags & NGX_LUA_RE_MODE_DFA) && n > ovecsize / 3) {
n = ovecsize / 3;
}
for (i = 0; i < n; i++) {
re->captures[i * 2] = ov[i * 2];
re->captures[i * 2 + 1] = ov[i * 2 + 1];
}
failed:
ngx_http_lua_pcre_malloc_done(old_pool);
return rc;
}
#else
int
ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
const u_char *s, size_t len, int pos)
@ -427,7 +810,8 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT];
rc = ngx_http_lua_regex_dfa_exec(re->regex, sd, &subj,
(int) pos, cap, ovecsize, ws,
sizeof(ws)/sizeof(ws[0]), exec_opts);
sizeof(ws) / sizeof(ws[0]),
exec_opts);
#else
@ -443,28 +827,19 @@ ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
return rc;
}
#endif
void
ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re)
{
ngx_pool_t *old_pool;
dd("destroy regex called");
if (re == NULL || re->pool == NULL) {
return;
}
if (re->regex_sd) {
old_pool = ngx_http_lua_pcre_malloc_init(re->pool);
#if LUA_HAVE_PCRE_JIT
pcre_free_study(re->regex_sd);
#else
pcre_free(re->regex_sd);
#endif
ngx_http_lua_pcre_malloc_done(old_pool);
re->regex_sd = NULL;
}
ngx_http_lua_regex_free_study_data(re->pool, re);
ngx_destroy_pool(re->pool);
}
@ -592,7 +967,13 @@ ngx_http_lua_ffi_max_regex_cache_size(void)
const char *
ngx_http_lua_ffi_pcre_version(void)
{
#if (NGX_PCRE2)
pcre2_config(PCRE2_CONFIG_VERSION, ngx_pcre2_version);
return ngx_pcre2_version;
#else
return pcre_version();
#endif
}

View file

@ -85,6 +85,23 @@ ngx_http_lua_ngx_req_read_body(lua_State *L)
return luaL_error(L, "request object not found");
}
/* http2 read body may break http2 stream process */
#if (NGX_HTTP_V2)
if (r->main->stream && r->headers_in.content_length_n < 0) {
return luaL_error(L, "http2 requests are not supported"
" without content-length header");
}
#endif
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.content_length_n < 0)
{
return luaL_error(L, "http3 requests are not supported"
" without content-length header");
}
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;
@ -229,15 +246,21 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L)
{
ngx_http_request_t *r;
int n;
size_t len;
size_t len, max;
size_t size, rest;
ngx_chain_t *cl;
u_char *p;
u_char *buf;
n = lua_gettop(L);
if (n != 0) {
return luaL_error(L, "expecting 0 arguments but seen %d", n);
if (n != 0 && n != 1) {
return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n);
}
max = 0;
if (n == 1) {
max = (size_t) luaL_checknumber(L, 1);
}
r = ngx_http_lua_get_req(L);
@ -265,6 +288,7 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L)
return 1;
}
len = (max > 0 && len > max) ? max : len;
lua_pushlstring(L, (char *) cl->buf->pos, len);
return 1;
}
@ -275,7 +299,13 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L)
for (; cl; cl = cl->next) {
dd("body chunk len: %d", (int) ngx_buf_size(cl->buf));
len += cl->buf->last - cl->buf->pos;
size = cl->buf->last - cl->buf->pos;
if (max > 0 && (len + size > max)) {
len = max;
break;
}
len += size;
}
if (len == 0) {
@ -286,8 +316,15 @@ ngx_http_lua_ngx_req_get_body_data(lua_State *L)
buf = (u_char *) lua_newuserdata(L, len);
p = buf;
for (cl = r->request_body->bufs; cl; cl = cl->next) {
p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos);
rest = len;
for (cl = r->request_body->bufs; cl != NULL && rest > 0; cl = cl->next) {
size = ngx_buf_size(cl->buf);
if (size > rest) { /* reach limit*/
size = rest;
}
p = ngx_copy(p, cl->buf->pos, size);
rest -= size;
}
lua_pushlstring(L, (char *) buf, len);
@ -312,6 +349,23 @@ ngx_http_lua_ngx_req_get_body_file(lua_State *L)
return luaL_error(L, "request object not found");
}
/* http2 read body may break http2 stream process */
#if (NGX_HTTP_V2)
if (r->main->stream && r->headers_in.content_length_n < 0) {
return luaL_error(L, "http2 requests are not supported"
" without content-length header");
}
#endif
#if (NGX_HTTP_V3)
if (r->http_version == NGX_HTTP_VERSION_30
&& r->headers_in.content_length_n < 0)
{
return luaL_error(L, "http3 requests are not supported"
" without content-length header");
}
#endif
ngx_http_lua_check_fake_request(L, r);
if (r->request_body == NULL || r->request_body->temp_file == NULL) {

View file

@ -140,7 +140,12 @@ ngx_http_lua_rewrite_handler(ngx_http_request_t *r)
return NGX_DONE;
}
/* http2 read body may break http2 stream process */
#if (NGX_HTTP_V2)
if (llcf->force_read_body && !ctx->read_body_done && !r->main->stream) {
#else
if (llcf->force_read_body && !ctx->read_body_done) {
#endif
r->request_body_in_single_buf = 1;
r->request_body_in_persistent_file = 1;
r->request_body_in_clean_file = 1;

Some files were not shown because too many files have changed in this diff Show more