mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
Soft merge branch 'dev' into branch '1.6'
This commit is contained in:
commit
cc0f189e7a
278 changed files with 4436 additions and 4265 deletions
19
.github/workflows/beta.yml
vendored
19
.github/workflows/beta.yml
vendored
|
|
@ -94,14 +94,12 @@ jobs:
|
|||
needs: [create-arm]
|
||||
strategy:
|
||||
matrix:
|
||||
linux: [ubuntu, ubuntu-noble, debian, fedora, rhel, rhel9]
|
||||
linux: [ubuntu, debian, fedora, rhel, rhel9]
|
||||
platforms: [linux/amd64, linux/arm64]
|
||||
include:
|
||||
- release: beta
|
||||
- linux: ubuntu
|
||||
package: deb
|
||||
- linux: ubuntu-noble
|
||||
package: deb
|
||||
- linux: debian
|
||||
package: deb
|
||||
- linux: fedora
|
||||
|
|
@ -181,17 +179,12 @@ jobs:
|
|||
needs: [wait-builds]
|
||||
strategy:
|
||||
matrix:
|
||||
linux: [ubuntu, ubuntu-noble, debian, fedora, el, el9]
|
||||
linux: [ubuntu, debian, fedora, el, el9]
|
||||
arch: [amd64, arm64]
|
||||
include:
|
||||
- release: beta
|
||||
repo: bunkerweb
|
||||
- linux: ubuntu
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: jammy
|
||||
package: deb
|
||||
- linux: ubuntu-noble
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: noble
|
||||
|
|
@ -204,7 +197,7 @@ jobs:
|
|||
- linux: fedora
|
||||
separator: "-"
|
||||
suffix: "1."
|
||||
version: 39
|
||||
version: 40
|
||||
package: rpm
|
||||
- linux: el
|
||||
separator: "-"
|
||||
|
|
@ -219,9 +212,6 @@ jobs:
|
|||
- linux: ubuntu
|
||||
arch: amd64
|
||||
package_arch: amd64
|
||||
- linux: ubuntu-noble
|
||||
arch: amd64
|
||||
package_arch: amd64
|
||||
- linux: debian
|
||||
arch: amd64
|
||||
package_arch: amd64
|
||||
|
|
@ -237,9 +227,6 @@ jobs:
|
|||
- linux: ubuntu
|
||||
arch: arm64
|
||||
package_arch: arm64
|
||||
- linux: ubuntu-noble
|
||||
arch: arm64
|
||||
package_arch: arm64
|
||||
- linux: debian
|
||||
arch: arm64
|
||||
package_arch: arm64
|
||||
|
|
|
|||
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
|
|
@ -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@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6
|
||||
uses: github/codeql-action/init@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql.yml
|
||||
setup-python-dependencies: false
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6
|
||||
uses: github/codeql-action/analyze@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
|
|
|||
6
.github/workflows/container-build.yml
vendored
6
.github/workflows/container-build.yml
vendored
|
|
@ -72,13 +72,13 @@ jobs:
|
|||
endpoint: ssh://root@arm
|
||||
platforms: linux/arm64,linux/arm/v7,linux/arm/v6
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- name: Login to ghcr
|
||||
if: inputs.PUSH == true
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
@ -117,7 +117,7 @@ jobs:
|
|||
# Check OS vulnerabilities
|
||||
- name: Check OS vulnerabilities
|
||||
if: ${{ inputs.CACHE_SUFFIX != 'arm' }}
|
||||
uses: aquasecurity/trivy-action@fd25fed6972e341ff0007ddb61f77e88103953c2 # v0.21.0
|
||||
uses: aquasecurity/trivy-action@595be6a0f6560a0a8fc419ddf630567fc623531d # v0.22.0
|
||||
with:
|
||||
vuln-type: os
|
||||
skip-dirs: /root/.cargo
|
||||
|
|
|
|||
24
.github/workflows/dev.yml
vendored
24
.github/workflows/dev.yml
vendored
|
|
@ -43,11 +43,11 @@ jobs:
|
|||
packages: write
|
||||
strategy:
|
||||
matrix:
|
||||
linux: [ubuntu, ubuntu-noble, debian, fedora, rhel, rhel9]
|
||||
linux: [ubuntu, debian, fedora, rhel, rhel9, ubuntu-jammy]
|
||||
include:
|
||||
- linux: ubuntu
|
||||
package: deb
|
||||
- linux: ubuntu-noble
|
||||
- linux: ubuntu-jammy
|
||||
package: deb
|
||||
- linux: debian
|
||||
package: deb
|
||||
|
|
@ -151,12 +151,12 @@ jobs:
|
|||
packages: write
|
||||
steps:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
@ -187,18 +187,12 @@ jobs:
|
|||
needs: [tests-ui-linux, tests-core-linux]
|
||||
strategy:
|
||||
matrix:
|
||||
linux: [ubuntu, ubuntu-noble, debian, fedora, el, el9]
|
||||
linux: [ubuntu, debian, fedora, el, el9, ubuntu-jammy]
|
||||
arch: [amd64]
|
||||
include:
|
||||
- release: dev
|
||||
repo: bunkerweb
|
||||
- linux: ubuntu
|
||||
package_arch: amd64
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: jammy
|
||||
package: deb
|
||||
- linux: ubuntu-noble
|
||||
package_arch: amd64
|
||||
separator: _
|
||||
suffix: ""
|
||||
|
|
@ -214,7 +208,7 @@ jobs:
|
|||
package_arch: x86_64
|
||||
separator: "-"
|
||||
suffix: "1."
|
||||
version: 39
|
||||
version: 40
|
||||
package: rpm
|
||||
- linux: el
|
||||
package_arch: x86_64
|
||||
|
|
@ -228,6 +222,12 @@ jobs:
|
|||
suffix: "1."
|
||||
version: 9
|
||||
package: rpm
|
||||
- linux: ubuntu-jammy
|
||||
package_arch: amd64
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: jammy
|
||||
package: deb
|
||||
uses: ./.github/workflows/push-packagecloud.yml
|
||||
with:
|
||||
SEPARATOR: ${{ matrix.separator }}
|
||||
|
|
|
|||
4
.github/workflows/linux-build.yml
vendored
4
.github/workflows/linux-build.yml
vendored
|
|
@ -81,12 +81,12 @@ jobs:
|
|||
endpoint: ssh://root@arm
|
||||
platforms: linux/arm64,linux/arm/v7,linux/arm/v6
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
|
|||
4
.github/workflows/push-docker.yml
vendored
4
.github/workflows/push-docker.yml
vendored
|
|
@ -35,12 +35,12 @@ jobs:
|
|||
- name: Check out repository code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
|
|||
18
.github/workflows/push-packagecloud.yml
vendored
18
.github/workflows/push-packagecloud.yml
vendored
|
|
@ -42,7 +42,7 @@ jobs:
|
|||
- name: Check out repository code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Install ruby
|
||||
uses: ruby/setup-ruby@943103cae7d3f1bb1e4951d5fcc7928b40e4b742 # v1.177.1
|
||||
uses: ruby/setup-ruby@d5fb7a202fc07872cb44f00ba8e6197b70cb0c55 # v1.179.0
|
||||
with:
|
||||
ruby-version: "3.0"
|
||||
- name: Install packagecloud
|
||||
|
|
@ -60,7 +60,7 @@ jobs:
|
|||
path: /tmp/${{ inputs.LINUX }}
|
||||
# Remove existing packages
|
||||
- name: Remove existing package
|
||||
if: inputs.LINUX != 'el9' && inputs.LINUX != 'ubuntu-noble'
|
||||
if: inputs.LINUX != 'el9' && inputs.LINUX != 'ubuntu-jammy'
|
||||
run: package_cloud yank bunkerity/${{ inputs.REPO }}/${{ inputs.LINUX }}/${{ inputs.VERSION }} bunkerweb${{ inputs.SEPARATOR }}${{ inputs.BW_VERSION }}${{ inputs.SEPARATOR }}${{ inputs.SUFFIX }}${{ inputs.PACKAGE_ARCH }}.${{ inputs.PACKAGE }}
|
||||
continue-on-error: true
|
||||
env:
|
||||
|
|
@ -71,9 +71,9 @@ jobs:
|
|||
continue-on-error: true
|
||||
env:
|
||||
PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
|
||||
- name: Remove existing package ubuntu-noble
|
||||
if: inputs.LINUX == 'ubuntu-noble'
|
||||
run: package_cloud yank bunkerity/${{ inputs.REPO }}/ubuntu/noble bunkerweb${{ inputs.SEPARATOR }}${{ inputs.BW_VERSION }}${{ inputs.SEPARATOR }}${{ inputs.SUFFIX }}${{ inputs.PACKAGE_ARCH }}.${{ inputs.PACKAGE }}
|
||||
- name: Remove existing package ubuntu-jammy
|
||||
if: inputs.LINUX == 'ubuntu-jammy'
|
||||
run: package_cloud yank bunkerity/${{ inputs.REPO }}/ubuntu/jammy bunkerweb${{ inputs.SEPARATOR }}${{ inputs.BW_VERSION }}${{ inputs.SEPARATOR }}${{ inputs.SUFFIX }}${{ inputs.PACKAGE_ARCH }}.${{ inputs.PACKAGE }}
|
||||
continue-on-error: true
|
||||
env:
|
||||
PACKAGECLOUD_TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
|
||||
|
|
@ -83,7 +83,7 @@ jobs:
|
|||
# run: sudo apt install -y rename && rename 's/[0-9]\.[0-9]\.[0-9]/testing/' /tmp/${{ inputs.LINUX }}/*.${{ inputs.PACKAGE }}
|
||||
# Push package
|
||||
- name: Push package to packagecloud
|
||||
if: inputs.LINUX != 'el9' && inputs.LINUX != 'ubuntu-noble'
|
||||
if: inputs.LINUX != 'el9' && inputs.LINUX != 'ubuntu-jammy'
|
||||
uses: danielmundi/upload-packagecloud@46cd0e61152bf952dbc0d1759e609d3d22649030 # v1
|
||||
with:
|
||||
PACKAGE-NAME: /tmp/${{ inputs.LINUX }}/*.${{ inputs.PACKAGE }}
|
||||
|
|
@ -100,12 +100,12 @@ jobs:
|
|||
PACKAGECLOUD-REPO: ${{ inputs.REPO }}
|
||||
PACKAGECLOUD-DISTRIB: el/9
|
||||
PACKAGECLOUD-TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
|
||||
- name: Push package to packagecloud for ubuntu-noble
|
||||
if: inputs.LINUX == 'ubuntu-noble'
|
||||
- name: Push package to packagecloud for ubuntu-jammy
|
||||
if: inputs.LINUX == 'ubuntu-jammy'
|
||||
uses: danielmundi/upload-packagecloud@46cd0e61152bf952dbc0d1759e609d3d22649030 # v1
|
||||
with:
|
||||
PACKAGE-NAME: /tmp/${{ inputs.LINUX }}/*.${{ inputs.PACKAGE }}
|
||||
PACKAGECLOUD-USERNAME: bunkerity
|
||||
PACKAGECLOUD-REPO: ${{ inputs.REPO }}
|
||||
PACKAGECLOUD-DISTRIB: ubuntu/noble
|
||||
PACKAGECLOUD-DISTRIB: ubuntu/jammy
|
||||
PACKAGECLOUD-TOKEN: ${{ secrets.PACKAGECLOUD_TOKEN }}
|
||||
|
|
|
|||
35
.github/workflows/release.yml
vendored
35
.github/workflows/release.yml
vendored
|
|
@ -104,17 +104,12 @@ jobs:
|
|||
needs: [create-arm]
|
||||
strategy:
|
||||
matrix:
|
||||
linux: [ubuntu, ubuntu-noble, debian, fedora, rhel, rhel9]
|
||||
linux: [ubuntu, debian, fedora, rhel, rhel9, ubuntu-jammy]
|
||||
platforms: [linux/amd64, linux/arm64]
|
||||
exclude:
|
||||
- linux: ubuntu-noble
|
||||
platforms: linux/arm64
|
||||
include:
|
||||
- release: latest
|
||||
- linux: ubuntu
|
||||
package: deb
|
||||
- linux: ubuntu-noble
|
||||
package: deb
|
||||
- linux: debian
|
||||
package: deb
|
||||
- linux: fedora
|
||||
|
|
@ -123,6 +118,8 @@ jobs:
|
|||
package: rpm
|
||||
- linux: rhel9
|
||||
package: rpm
|
||||
- linux: ubuntu-jammy
|
||||
package: deb
|
||||
uses: ./.github/workflows/linux-build.yml
|
||||
with:
|
||||
RELEASE: ${{ matrix.release }}
|
||||
|
|
@ -196,20 +193,12 @@ jobs:
|
|||
needs: [wait-builds]
|
||||
strategy:
|
||||
matrix:
|
||||
linux: [ubuntu, ubuntu-noble, debian, fedora, el, el9]
|
||||
linux: [ubuntu, debian, fedora, el, el9, ubuntu-jammy]
|
||||
arch: [amd64, arm64]
|
||||
exclude:
|
||||
- linux: ubuntu-noble
|
||||
arch: arm64
|
||||
include:
|
||||
- release: latest
|
||||
repo: bunkerweb
|
||||
- linux: ubuntu
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: jammy
|
||||
package: deb
|
||||
- linux: ubuntu-noble
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: noble
|
||||
|
|
@ -222,7 +211,7 @@ jobs:
|
|||
- linux: fedora
|
||||
separator: "-"
|
||||
suffix: "1."
|
||||
version: 39
|
||||
version: 40
|
||||
package: rpm
|
||||
- linux: el
|
||||
separator: "-"
|
||||
|
|
@ -234,12 +223,14 @@ jobs:
|
|||
suffix: "1."
|
||||
version: 9
|
||||
package: rpm
|
||||
- linux: ubuntu-jammy
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: jammy
|
||||
package: deb
|
||||
- linux: ubuntu
|
||||
arch: amd64
|
||||
package_arch: amd64
|
||||
- linux: ubuntu-noble
|
||||
arch: amd64
|
||||
package_arch: amd64
|
||||
- linux: debian
|
||||
arch: amd64
|
||||
package_arch: amd64
|
||||
|
|
@ -252,6 +243,9 @@ jobs:
|
|||
- linux: el9
|
||||
arch: amd64
|
||||
package_arch: x86_64
|
||||
- linux: ubuntu-jammy
|
||||
arch: amd64
|
||||
package_arch: amd64
|
||||
- linux: ubuntu
|
||||
arch: arm64
|
||||
package_arch: arm64
|
||||
|
|
@ -267,6 +261,9 @@ jobs:
|
|||
- linux: el9
|
||||
arch: arm64
|
||||
package_arch: aarch64
|
||||
- linux: ubuntu-jammy
|
||||
arch: arm64
|
||||
package_arch: arm64
|
||||
uses: ./.github/workflows/push-packagecloud.yml
|
||||
with:
|
||||
SEPARATOR: ${{ matrix.separator }}
|
||||
|
|
|
|||
2
.github/workflows/scorecards-analysis.yml
vendored
2
.github/workflows/scorecards-analysis.yml
vendored
|
|
@ -25,6 +25,6 @@ jobs:
|
|||
results_format: sarif
|
||||
publish_results: true
|
||||
- name: "Upload SARIF results to code scanning"
|
||||
uses: github/codeql-action/upload-sarif@9fdb3e49720b44c48891d036bb502feb25684276 # v3.25.6
|
||||
uses: github/codeql-action/upload-sarif@2e230e8fe0ad3a14a340ad0815ddb96d599d2aff # v3.25.8
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
|
|||
2
.github/workflows/staging-create-infra.yml
vendored
2
.github/workflows/staging-create-infra.yml
vendored
|
|
@ -28,7 +28,7 @@ jobs:
|
|||
uses: azure/setup-kubectl@3e0aec4d80787158d308d7b364cb1b702e7feb7f # v4.0.0
|
||||
if: inputs.TYPE == 'k8s'
|
||||
with:
|
||||
version: "v1.28.6"
|
||||
version: "v1.29.1"
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
|
||||
if: inputs.TYPE != 'k8s'
|
||||
|
|
|
|||
2
.github/workflows/staging-delete-infra.yml
vendored
2
.github/workflows/staging-delete-infra.yml
vendored
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
- uses: azure/setup-kubectl@3e0aec4d80787158d308d7b364cb1b702e7feb7f # v4.0.0
|
||||
if: inputs.TYPE == 'k8s'
|
||||
with:
|
||||
version: "v1.28.2"
|
||||
version: "v1.29.1"
|
||||
# Remove infra
|
||||
- run: kubectl delete daemonsets,replicasets,services,deployments,pods,rc,ingress,statefulsets --all --all-namespaces --timeout=60s ; kubectl delete pvc --all --timeout=60s ; kubectl delete pv --all --timeout=60s
|
||||
if: inputs.TYPE == 'k8s'
|
||||
|
|
|
|||
22
.github/workflows/staging-tests.yml
vendored
22
.github/workflows/staging-tests.yml
vendored
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
- name: Checkout source code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
@ -69,15 +69,12 @@ jobs:
|
|||
- uses: azure/setup-kubectl@3e0aec4d80787158d308d7b364cb1b702e7feb7f # v4.0.0
|
||||
if: inputs.TYPE == 'k8s'
|
||||
with:
|
||||
version: "v1.28.2"
|
||||
version: "v1.29.1"
|
||||
- uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0
|
||||
if: inputs.TYPE == 'k8s'
|
||||
- name: Pull BW linux ubuntu test image
|
||||
if: inputs.TYPE == 'linux'
|
||||
run: docker pull ghcr.io/bunkerity/ubuntu-tests:testing && docker tag ghcr.io/bunkerity/ubuntu-tests:testing local/ubuntu:latest
|
||||
- name: Pull BW linux ubuntu noble test image
|
||||
if: inputs.TYPE == 'linux'
|
||||
run: docker pull ghcr.io/bunkerity/ubuntu-noble-tests:testing && docker tag ghcr.io/bunkerity/ubuntu-noble-tests:testing local/ubuntu-noble:latest
|
||||
- name: Pull BW linux debian test image
|
||||
if: inputs.TYPE == 'linux'
|
||||
run: docker pull ghcr.io/bunkerity/debian-tests:testing && docker tag ghcr.io/bunkerity/debian-tests:testing local/debian:latest
|
||||
|
|
@ -90,6 +87,9 @@ jobs:
|
|||
- name: Pull BW linux rhel9 test image
|
||||
if: inputs.TYPE == 'linux'
|
||||
run: docker pull ghcr.io/bunkerity/rhel9-tests:testing && docker tag ghcr.io/bunkerity/rhel9-tests:testing local/rhel9:latest
|
||||
- name: Pull BW linux ubuntu jammy test image
|
||||
if: inputs.TYPE == 'linux'
|
||||
run: docker pull ghcr.io/bunkerity/ubuntu-jammy-tests:testing && docker tag ghcr.io/bunkerity/ubuntu-jammy-tests:testing local/ubuntu-jammy:latest
|
||||
# Do tests
|
||||
- name: Run tests
|
||||
if: inputs.TYPE == 'docker'
|
||||
|
|
@ -124,12 +124,6 @@ jobs:
|
|||
env:
|
||||
TEST_DOMAINS: ${{ secrets.TEST_DOMAINS_LINUX }}
|
||||
ROOT_DOMAIN: ${{ secrets.ROOT_DOMAIN }}
|
||||
- name: Run Linux ubuntu noble tests
|
||||
if: inputs.TYPE == 'linux'
|
||||
run: export $(echo "$TEST_DOMAINS" | xargs) && ./tests/main.py "linux" "ubuntu-noble"
|
||||
env:
|
||||
TEST_DOMAINS: ${{ secrets.TEST_DOMAINS_LINUX }}
|
||||
ROOT_DOMAIN: ${{ secrets.ROOT_DOMAIN }}
|
||||
- name: Run Linux debian tests
|
||||
if: inputs.TYPE == 'linux'
|
||||
run: export $(echo "$TEST_DOMAINS" | xargs) && ./tests/main.py "linux" "debian"
|
||||
|
|
@ -154,3 +148,9 @@ jobs:
|
|||
env:
|
||||
TEST_DOMAINS: ${{ secrets.TEST_DOMAINS_LINUX }}
|
||||
ROOT_DOMAIN: ${{ secrets.ROOT_DOMAIN }}
|
||||
- name: Run Linux ubuntu-jammy tests
|
||||
if: inputs.TYPE == 'linux'
|
||||
run: export $(echo "$TEST_DOMAINS" | xargs) && ./tests/main.py "linux" "ubuntu-jammy"
|
||||
env:
|
||||
TEST_DOMAINS: ${{ secrets.TEST_DOMAINS_LINUX }}
|
||||
ROOT_DOMAIN: ${{ secrets.ROOT_DOMAIN }}
|
||||
|
|
|
|||
26
.github/workflows/staging.yml
vendored
26
.github/workflows/staging.yml
vendored
|
|
@ -43,12 +43,10 @@ jobs:
|
|||
packages: write
|
||||
strategy:
|
||||
matrix:
|
||||
linux: [ubuntu, ubuntu-noble, debian, fedora, rhel, rhel9]
|
||||
linux: [ubuntu, debian, fedora, rhel, rhel9, ubuntu-jammy]
|
||||
include:
|
||||
- linux: ubuntu
|
||||
package: deb
|
||||
- linux: ubuntu-noble
|
||||
package: deb
|
||||
- linux: debian
|
||||
package: deb
|
||||
- linux: fedora
|
||||
|
|
@ -57,6 +55,8 @@ jobs:
|
|||
package: rpm
|
||||
- linux: rhel9
|
||||
package: rpm
|
||||
- linux: ubuntu-jammy
|
||||
package: deb
|
||||
uses: ./.github/workflows/linux-build.yml
|
||||
with:
|
||||
RELEASE: testing
|
||||
|
|
@ -199,12 +199,12 @@ jobs:
|
|||
packages: write
|
||||
steps:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
@ -223,18 +223,12 @@ jobs:
|
|||
needs: [staging-tests, tests-ui-linux, tests-core-linux]
|
||||
strategy:
|
||||
matrix:
|
||||
linux: [ubuntu, ubuntu-noble, debian, fedora, el, el9]
|
||||
linux: [ubuntu, debian, fedora, el, el9, ubuntu-jammy]
|
||||
arch: [amd64]
|
||||
include:
|
||||
- release: testing
|
||||
repo: bunkerweb
|
||||
- linux: ubuntu
|
||||
package_arch: amd64
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: jammy
|
||||
package: deb
|
||||
- linux: ubuntu-noble
|
||||
package_arch: amd64
|
||||
separator: _
|
||||
suffix: ""
|
||||
|
|
@ -250,7 +244,7 @@ jobs:
|
|||
package_arch: x86_64
|
||||
separator: "-"
|
||||
suffix: "1."
|
||||
version: 39
|
||||
version: 40
|
||||
package: rpm
|
||||
- linux: el
|
||||
package_arch: x86_64
|
||||
|
|
@ -264,6 +258,12 @@ jobs:
|
|||
suffix: "1."
|
||||
version: 9
|
||||
package: rpm
|
||||
- linux: ubuntu-jammy
|
||||
package_arch: amd64
|
||||
separator: _
|
||||
suffix: ""
|
||||
version: jammy
|
||||
package: deb
|
||||
uses: ./.github/workflows/push-packagecloud.yml
|
||||
with:
|
||||
SEPARATOR: ${{ matrix.separator }}
|
||||
|
|
|
|||
35
.github/workflows/test-core-linux.yml
vendored
35
.github/workflows/test-core-linux.yml
vendored
|
|
@ -12,15 +12,15 @@ on:
|
|||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
# Prepare
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Set up Python 3.9
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
|
||||
with:
|
||||
python-version: "3.9"
|
||||
python-version: "3.12"
|
||||
- name: Install Firefox manually and dependencies
|
||||
run: |
|
||||
sudo add-apt-repository ppa:mozillateam/ppa -y
|
||||
|
|
@ -31,10 +31,12 @@ jobs:
|
|||
Pin-Priority: 1001
|
||||
|
||||
Package: firefox
|
||||
Pin: version 1:1snap1-0ubuntu2
|
||||
Pin: version 1:1snap1-0ubuntu5
|
||||
Pin-Priority: -1
|
||||
' | sudo tee /etc/apt/preferences.d/mozilla-firefox
|
||||
sudo apt install --no-install-recommends -y openssl git nodejs tar bzip2 wget curl grep libx11-xcb1 libappindicator3-1 libasound2 libdbus-glib-1-2 libxtst6 libxt6 php-fpm unzip firefox
|
||||
export NEEDRESTART_SUSPEND=1
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo -E apt install --no-install-recommends -y openssl git nodejs tar bzip2 wget curl grep libx11-xcb1 libappindicator3-1 libasound2t64 libdbus-glib-1-2 libxtst6 libxt6 php-fpm unzip firefox
|
||||
- name: Download geckodriver
|
||||
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
|
||||
with:
|
||||
|
|
@ -47,7 +49,7 @@ jobs:
|
|||
sudo chmod +x /usr/local/bin/geckodriver
|
||||
rm -f geckodriver.tar.gz
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
@ -61,11 +63,13 @@ jobs:
|
|||
docker rm "$container_id"
|
||||
- name: Install NGINX
|
||||
run: |
|
||||
sudo apt install -y gnupg2 ca-certificates lsb-release ubuntu-keyring
|
||||
export NEEDRESTART_SUSPEND=1
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo -E apt install -y gnupg2 ca-certificates lsb-release ubuntu-keyring
|
||||
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
|
||||
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
|
||||
sudo apt update
|
||||
sudo apt install -y nginx=1.26.0-1~jammy
|
||||
sudo -E apt install -y nginx=1.26.1-2~noble
|
||||
- name: Fix version without a starting number
|
||||
if: inputs.RELEASE == 'testing' || inputs.RELEASE == 'dev'
|
||||
run: echo "force-bad-version" | sudo tee -a /etc/dpkg/dpkg.cfg
|
||||
|
|
@ -75,9 +79,9 @@ jobs:
|
|||
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
|
||||
echo "127.0.0.1 bwadm.example.com" | sudo tee -a /etc/hosts
|
||||
sudo cp ./tests/www-deb.conf /etc/php/8.1/fpm/pool.d/www.conf
|
||||
sudo systemctl stop php8.1-fpm
|
||||
sudo systemctl start php8.1-fpm
|
||||
sudo cp ./tests/www-deb.conf /etc/php/8.3/fpm/pool.d/www.conf
|
||||
sudo systemctl stop php8.3-fpm
|
||||
sudo systemctl start php8.3-fpm
|
||||
# BunkerWeb
|
||||
sudo mkdir -p /etc/bunkerweb
|
||||
echo "SERVER_NAME=www.example.com" | sudo tee /etc/bunkerweb/variables.env
|
||||
|
|
@ -92,12 +96,15 @@ jobs:
|
|||
sudo chown nginx:nginx /etc/bunkerweb/variables.env
|
||||
sudo chmod 777 /etc/bunkerweb/variables.env
|
||||
- name: Install BunkerWeb
|
||||
run: sudo apt install -fy /tmp/bunkerweb.deb
|
||||
run: |
|
||||
export NEEDRESTART_SUSPEND=1
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo -E apt install -fy /tmp/bunkerweb.deb
|
||||
- name: Run tests
|
||||
run: |
|
||||
export MAKEFLAGS="-j $(nproc)"
|
||||
pip install --no-cache-dir --ignore-installed --require-hashes -r src/deps/requirements-deps.txt
|
||||
pip install --break-system-packages --no-cache-dir --ignore-installed --require-hashes -r src/deps/requirements-deps.txt
|
||||
cd tests/core/${{ inputs.TEST }}
|
||||
find . -name "requirements.txt" -exec pip install --no-cache-dir --require-hashes --no-deps -r {} \;
|
||||
find . -name "requirements.txt" -exec pip install --break-system-packages --no-cache-dir --require-hashes --no-deps -r {} \;
|
||||
sudo truncate -s 0 /var/log/bunkerweb/error.log
|
||||
./test.sh "linux"
|
||||
|
|
|
|||
2
.github/workflows/test-core.yml
vendored
2
.github/workflows/test-core.yml
vendored
|
|
@ -18,7 +18,7 @@ jobs:
|
|||
- name: Checkout source code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
|
|||
29
.github/workflows/tests-ui-linux.yml
vendored
29
.github/workflows/tests-ui-linux.yml
vendored
|
|
@ -12,15 +12,15 @@ on:
|
|||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
# Prepare
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Set up Python 3.9
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0
|
||||
with:
|
||||
python-version: "3.9"
|
||||
python-version: "3.12"
|
||||
- name: Install Firefox manually and dependencies
|
||||
run: |
|
||||
sudo add-apt-repository ppa:mozillateam/ppa -y
|
||||
|
|
@ -31,10 +31,12 @@ jobs:
|
|||
Pin-Priority: 1001
|
||||
|
||||
Package: firefox
|
||||
Pin: version 1:1snap1-0ubuntu2
|
||||
Pin: version 1:1snap1-0ubuntu5
|
||||
Pin-Priority: -1
|
||||
' | sudo tee /etc/apt/preferences.d/mozilla-firefox
|
||||
sudo apt install --no-install-recommends -y openssl git nodejs tar bzip2 wget curl grep libx11-xcb1 libappindicator3-1 libasound2 libdbus-glib-1-2 libxtst6 libxt6 php-fpm unzip firefox
|
||||
export NEEDRESTART_SUSPEND=1
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo -E apt install --no-install-recommends -y openssl git nodejs tar bzip2 wget curl grep libx11-xcb1 libappindicator3-1 libasound2t64 libdbus-glib-1-2 libxtst6 libxt6 php-fpm unzip firefox
|
||||
- name: Download geckodriver
|
||||
uses: nick-fields/retry@7152eba30c6575329ac0576536151aca5a72780e # v3.0.0
|
||||
with:
|
||||
|
|
@ -47,7 +49,7 @@ jobs:
|
|||
sudo chmod +x /usr/local/bin/geckodriver
|
||||
rm -f geckodriver.tar.gz
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
@ -61,11 +63,13 @@ jobs:
|
|||
docker rm "$container_id"
|
||||
- name: Install NGINX
|
||||
run: |
|
||||
sudo apt install -y gnupg2 ca-certificates lsb-release ubuntu-keyring
|
||||
export NEEDRESTART_SUSPEND=1
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo -E apt install -y gnupg2 ca-certificates lsb-release ubuntu-keyring
|
||||
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
|
||||
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list
|
||||
sudo apt update
|
||||
sudo apt install -y nginx=1.26.0-1~jammy
|
||||
sudo -E apt install -y nginx=1.26.1-2~noble
|
||||
- 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
|
||||
|
|
@ -98,12 +102,15 @@ 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
|
||||
run: |
|
||||
export NEEDRESTART_SUSPEND=1
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
sudo -E apt install -fy /tmp/bunkerweb.deb
|
||||
- name: Run tests
|
||||
run: |
|
||||
export MAKEFLAGS="-j $(nproc)"
|
||||
pip install --no-cache-dir --ignore-installed --require-hashes -r src/deps/requirements-deps.txt
|
||||
pip install --no-cache-dir --require-hashes -r tests/ui/requirements.txt
|
||||
pip install --break-system-packages --no-cache-dir --ignore-installed --require-hashes -r src/deps/requirements-deps.txt
|
||||
pip install --break-system-packages --no-cache-dir --require-hashes -r tests/ui/requirements.txt
|
||||
cd ./tests/ui
|
||||
touch test.txt
|
||||
zip test.zip test.txt
|
||||
|
|
|
|||
2
.github/workflows/tests-ui.yml
vendored
2
.github/workflows/tests-ui.yml
vendored
|
|
@ -17,7 +17,7 @@ jobs:
|
|||
- name: Checkout source code
|
||||
uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0
|
||||
uses: docker/login-action@0d4c9c5ea7693da7b068278f7b52bda2a190a446 # v3.2.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
|
|
|||
|
|
@ -13,3 +13,7 @@ src/ui/templates/account.html:hashicorp-tf-password:162
|
|||
src/common/core/errors/files/error.html:aws-access-token:20
|
||||
src/deps/src/nginx/src/event/quic/ngx_event_quic_protection.c:generic-api-key:164
|
||||
src/deps/src/nginx/src/event/quic/ngx_event_quic_protection.c:generic-api-key:165
|
||||
src/deps/src/lua-resty-openssl/lib/resty/openssl/pkey.lua:generic-api-key:438
|
||||
src/deps/src/lua-resty-openssl/lib/resty/openssl/pkey.lua:generic-api-key:439
|
||||
src/deps/src/lua-resty-openssl/lib/resty/openssl/pkey.lua:generic-api-key:440
|
||||
src/deps/src/lua-resty-openssl/lib/resty/openssl/pkey.lua:generic-api-key:441
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ repos:
|
|||
exclude: ^src/(bw/lua/middleclass.lua|common/core/antibot/captcha.lua)$
|
||||
|
||||
- repo: https://github.com/lunarmodules/luacheck
|
||||
rev: 418f48976c73be697fe64b0eba9ea9821ac9bca8 # frozen: v1.1.2
|
||||
rev: cc089e3f65acdd1ef8716cc73a3eca24a6b845e4 # frozen: v1.2.0
|
||||
hooks:
|
||||
- id: luacheck
|
||||
exclude: ^src/(bw/lua/middleclass.lua|common/core/antibot/captcha.lua)$
|
||||
|
|
@ -57,7 +57,7 @@ repos:
|
|||
exclude: ^tests/
|
||||
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: 6e41aba91fb32e9feb741a6258eefeb9c6e4a482 # frozen: v2.2.6
|
||||
rev: 193cd7d27cd571f79358af09a8fb8997e54f8fff # frozen: v2.3.0
|
||||
hooks:
|
||||
- id: codespell
|
||||
name: Codespell Spell Checker
|
||||
|
|
|
|||
18
CHANGELOG.md
18
CHANGELOG.md
|
|
@ -2,11 +2,29 @@
|
|||
|
||||
## v1.5.8 - ????/??/??
|
||||
|
||||
- [LINUX] Support Fedora 40 and drop support of Fedora 39
|
||||
- [BUGFIX] Fix potential errors when upgrading from a previous version
|
||||
- [BUGFIX] Fix rare bug on the web UI when editing the SERVER_NAME setting of a service
|
||||
- [BUGFIX] Fix potential race conditions between the autoconf and the scheduler waiting for each other indefinitely
|
||||
- [BUGFIX] Fix Let's Encrypt certificate renewal when a certificate date changes by forcing the renewal
|
||||
- [BUGFIX] Fix issues with k8s integration and the save_config.py script
|
||||
- [FEATURE] Add nightly build of the OWASP coreruleset that are automatically downloaded and updated
|
||||
- [FEATURE] Enhance security on error pages, default server page and loading page by adding a custom `Content-Security-Policy` header with nonces and removing the `Server` header
|
||||
- [FEATURE] Add new DATABASE_URI_READONLY setting to allow setting up a fallback read-only database URI in case the main database URI is not available
|
||||
- [FEATURE] Add automatic fallback to either read-only on the primary database or to the read-only database URI when the main database URI is not available and automatically switch back to the main database URI when it becomes available again
|
||||
- [FEATURE] Add experimental support of HTTP/3 (QUIC)
|
||||
- [FEATURE] Optimize the way the scheduler handles jobs and the way the jobs are executed
|
||||
- [FEATURE] Optimize the way the cache files are being refreshed from the database
|
||||
- [UI] Force HTTPS on setup wizard
|
||||
- [UI] Fallback to self-signed certificate when UI is installed with setup wizard and let's encrypt is not used
|
||||
- [UI] Add OVERRIDE_ADMIN_CREDS environment variable to allow overriding the default admin credentials even if an admin user already exists
|
||||
- [UI] Optimize the way the UI handles the requests and the responses
|
||||
- [AUTOCONF] Refactor Autoconf config parsing and saving logic so that it doesn't override the scheduler or UI config every time
|
||||
- [MISC] Update logger format and datefmt for better readability
|
||||
- [DEPS] Updated NGINX version to v1.26.1
|
||||
- [DEPS] Updated stream-lua-nginx-module version to the latest commit to incorporate the latest changes and fixes for NGINX v1.26
|
||||
- [DEPS] Updated coreruleset-v4 version to v4.3.0
|
||||
- [DEPS] Updated lua-resty-openssl version to v1.4.0
|
||||
|
||||
## v1.5.7 - 2024/05/14
|
||||
|
||||
|
|
|
|||
16
README.md
16
README.md
|
|
@ -214,6 +214,16 @@ In other words, the scheduler is the brain of BunkerWeb.
|
|||
|
||||
# Setup
|
||||
|
||||
## BunkerWeb Cloud
|
||||
|
||||
<p align="center">
|
||||
<img alt="Docker banner" src="https://github.com/bunkerity/bunkerweb/raw/v1.5.8/docs/assets/img/bunkerweb-cloud.webp" />
|
||||
</p>
|
||||
|
||||
BunkerWeb Cloud is the easiest way to get started with BunkerWeb. It offers you a fully managed BunkerWeb service with no hassle. Think of a like a BunkerWeb-as-a-Service !
|
||||
|
||||
You will find more information about BunkerWeb Cloud beta [here](https://www.bunkerweb.io/cloud?utm_campaign=self&utm_source=docs) and you can apply for free [in the BunkerWeb panel](https://panel.bunkerweb.io/order/bunkerweb-cloud/14?utm_campaign=self&utm_source=docs).
|
||||
|
||||
## Docker
|
||||
|
||||
<p align="center">
|
||||
|
|
@ -273,9 +283,9 @@ You will find more information in the [Kubernetes section](https://docs.bunkerwe
|
|||
List of supported Linux distros :
|
||||
|
||||
- Debian 12 "Bookworm"
|
||||
- Ubuntu 22.04 "Jammy"
|
||||
- Ubuntu 24.04 "Noble"
|
||||
- Fedora 39
|
||||
- Ubuntu 22.04 "Noble"
|
||||
- Ubuntu 24.04 "Jammy"
|
||||
- Fedora 40
|
||||
- RHEL 8.9
|
||||
- RHEL 9.4
|
||||
|
||||
|
|
|
|||
BIN
docs/assets/img/bunkerweb-cloud.webp
Normal file
BIN
docs/assets/img/bunkerweb-cloud.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
|
|
@ -1,5 +1,19 @@
|
|||
# Integrations
|
||||
|
||||
## BunkerWeb Cloud
|
||||
|
||||
<figure markdown>
|
||||
{ align=center, width="600" }
|
||||
<figcaption>BunkerWeb Cloud</figcaption>
|
||||
</figure>
|
||||
|
||||
!!! example "Beta phase"
|
||||
BunkerWeb Cloud offer is in beta phase. We are actively getting feedbacks from our precious beta tester to improve the offer.
|
||||
|
||||
BunkerWeb Cloud is the easiest way to get started with BunkerWeb. It offers you a fully managed BunkerWeb service with no hassle. Think of a like a BunkerWeb-as-a-Service !
|
||||
|
||||
You will find more information about BunkerWeb Cloud beta [here](https://www.bunkerweb.io/cloud?utm_campaign=self&utm_source=docs) and you can apply for free [in the BunkerWeb panel](https://panel.bunkerweb.io/order/bunkerweb-cloud/14?utm_campaign=self&utm_source=docs).
|
||||
|
||||
## Docker
|
||||
|
||||
<figure markdown>
|
||||
|
|
@ -316,11 +330,11 @@ Supported Linux distributions for BunkerWeb (amd64/x86_64 and arm64/aarch64 arch
|
|||
- Debian 12 "Bookworm"
|
||||
- Ubuntu 22.04 "Jammy"
|
||||
- Ubuntu 24.04 "Noble"
|
||||
- Fedora 39
|
||||
- Fedora 40
|
||||
- Red Hat Enterprise Linux (RHEL) 8.9
|
||||
- Red Hat Enterprise Linux (RHEL) 9.4
|
||||
|
||||
Please ensure that you have **NGINX 1.26.0 installed before installing BunkerWeb**. For all distributions, except Fedora, it is mandatory to use prebuilt packages from the [official NGINX repository](https://nginx.org/en/linux_packages.html). Compiling NGINX from source or using packages from different repositories will not work with the official prebuilt packages of BunkerWeb. However, you have the option to build BunkerWeb from source.
|
||||
Please ensure that you have **NGINX 1.26.1 installed before installing BunkerWeb**. For all distributions, except Fedora, it is mandatory to use prebuilt packages from the [official NGINX repository](https://nginx.org/en/linux_packages.html). Compiling NGINX from source or using packages from different repositories will not work with the official prebuilt packages of BunkerWeb. However, you have the option to build BunkerWeb from source.
|
||||
|
||||
To simplify the installation process, Linux package repositories for BunkerWeb are available on [PackageCloud](https://packagecloud.io/bunkerity/bunkerweb). They provide a bash script that automatically adds and trusts the repository. You can follow the provided script for automatic setup, or opt for [manual installation](https://packagecloud.io/bunkerity/bunkerweb/install) instructions if you prefer.
|
||||
|
||||
|
|
@ -337,11 +351,11 @@ To simplify the installation process, Linux package repositories for BunkerWeb a
|
|||
| sudo tee /etc/apt/sources.list.d/nginx.list
|
||||
```
|
||||
|
||||
You should now be able to install NGINX 1.26.0 :
|
||||
You should now be able to install NGINX 1.26.1 :
|
||||
|
||||
```shell
|
||||
sudo apt update && \
|
||||
sudo apt install -y nginx=1.26.0-1~$(lsb_release -cs)
|
||||
sudo apt install -y nginx=1.26.1-2~$(lsb_release -cs)
|
||||
```
|
||||
|
||||
!!! warning "Testing/dev version"
|
||||
|
|
@ -384,11 +398,11 @@ To simplify the installation process, Linux package repositories for BunkerWeb a
|
|||
| sudo tee /etc/apt/sources.list.d/nginx.list
|
||||
```
|
||||
|
||||
You should now be able to install NGINX 1.26.0 :
|
||||
You should now be able to install NGINX 1.26.1 :
|
||||
|
||||
```shell
|
||||
sudo apt update && \
|
||||
sudo apt install -y nginx=1.26.0-1~$(lsb_release -cs)
|
||||
sudo apt install -y nginx=1.26.1-2~$(lsb_release -cs)
|
||||
```
|
||||
|
||||
!!! warning "Testing/dev version"
|
||||
|
|
@ -420,10 +434,17 @@ To simplify the installation process, Linux package repositories for BunkerWeb a
|
|||
|
||||
=== "Fedora"
|
||||
|
||||
Fedora already provides NGINX 1.26.0 that we support :
|
||||
!!! info "Fedora Update Testing"
|
||||
If you can't find the NGINX version listed in the stable repository, you can enable the `updates-testing` repository :
|
||||
|
||||
```shell
|
||||
sudo dnf config-manager --set-enabled updates-testing
|
||||
```
|
||||
|
||||
Fedora already provides NGINX 1.26.1 that we support :
|
||||
|
||||
```shell
|
||||
sudo dnf install -y nginx-1.26.0
|
||||
sudo dnf install -y nginx-1.26.1
|
||||
```
|
||||
|
||||
Optional step : if you want to automatically enable the [setup wizard](web-ui.md#setup-wizard) when BunkerWeb is installed, export the following variable :
|
||||
|
|
@ -471,10 +492,10 @@ To simplify the installation process, Linux package repositories for BunkerWeb a
|
|||
module_hotfixes=true
|
||||
```
|
||||
|
||||
You should now be able to install NGINX 1.26.0 :
|
||||
You should now be able to install NGINX 1.26.1 :
|
||||
|
||||
```shell
|
||||
sudo dnf install nginx-1.26.0
|
||||
sudo dnf install nginx-1.26.1
|
||||
```
|
||||
|
||||
Optional step : if you want to automatically enable the [setup wizard](web-ui.md#setup-wizard) when BunkerWeb is installed, export the following variable :
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ But dedicating time to a specific technology may not be easy depending on your b
|
|||
|
||||
Getting professional services in addition to the open-source or PRO version is the ideal solution to cover your business needs. You can focus on your top priorities and rely on a trusted partner when it comes to web security.
|
||||
|
||||
Please note that professionnal services are directly offered by [Bunkerity](https://www.bunkerity.com/?utm_campaign=self&utm_source=doc), the company maintaining the BunkerWeb project, through our [BunkerWeb Panel](https://panel.bunkerweb.io/?utm_campaign=self&utm_source=doc) online platform.
|
||||
Please note that professional services are directly offered by [Bunkerity](https://www.bunkerity.com/?utm_campaign=self&utm_source=doc), the company maintaining the BunkerWeb project, through our [BunkerWeb Panel](https://panel.bunkerweb.io/?utm_campaign=self&utm_source=doc) online platform.
|
||||
|
||||
## Which professional services do you offer ?
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
mike==2.1.1
|
||||
mkdocs-material[imaging]==9.5.24
|
||||
mkdocs-print-site-plugin==2.4.1
|
||||
mkdocs-material[imaging]==9.5.26
|
||||
mkdocs-print-site-plugin==2.5.0
|
||||
pytablewriter==1.2.0
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ cairosvg==2.7.1 \
|
|||
--hash=sha256:432531d72347291b9a9ebfb6777026b607563fd8719c46ee742db0aef7271ba0 \
|
||||
--hash=sha256:8a5222d4e6c3f86f1f7046b63246877a63b49923a1cd202184c3a634ef546b3b
|
||||
# via mkdocs-material
|
||||
certifi==2024.2.2 \
|
||||
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
||||
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
||||
certifi==2024.6.2 \
|
||||
--hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \
|
||||
--hash=sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56
|
||||
# via requests
|
||||
cffi==1.16.0 \
|
||||
--hash=sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc \
|
||||
|
|
@ -317,9 +317,9 @@ mkdocs-get-deps==0.2.0 \
|
|||
--hash=sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c \
|
||||
--hash=sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134
|
||||
# via mkdocs
|
||||
mkdocs-material==9.5.24 \
|
||||
--hash=sha256:02d5aaba0ee755e707c3ef6e748f9acb7b3011187c0ea766db31af8905078a34 \
|
||||
--hash=sha256:e12cd75954c535b61e716f359cf2a5056bf4514889d17161fdebd5df4b0153c6
|
||||
mkdocs-material==9.5.26 \
|
||||
--hash=sha256:56aeb91d94cffa43b6296fa4fbf0eb7c840136e563eecfd12c2d9e92e50ba326 \
|
||||
--hash=sha256:5d01fb0aa1c7946a1e3ae8689aa2b11a030621ecb54894e35aabb74c21016312
|
||||
# via
|
||||
# -r requirements.in
|
||||
# mkdocs-print-site-plugin
|
||||
|
|
@ -327,9 +327,9 @@ mkdocs-material-extensions==1.3.1 \
|
|||
--hash=sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443 \
|
||||
--hash=sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31
|
||||
# via mkdocs-material
|
||||
mkdocs-print-site-plugin==2.4.1 \
|
||||
--hash=sha256:8c05bdd6b34095fdfdb77a37a117106d4ba362ac5145a1664a3bef53b8cc9ba5 \
|
||||
--hash=sha256:c62eda1d47b65e48aa5a9316cb8ea93c035a342b5648b84bd892f48729aea6c9
|
||||
mkdocs-print-site-plugin==2.5.0 \
|
||||
--hash=sha256:48b3d41ae80384de72062b2712fce677f2e46d8364d9fe603ba837b0cf7156a4 \
|
||||
--hash=sha256:95dccc8d5cc8a59da67815a2d3304ef0101b065e363f2b9ac919c23d6196dd24
|
||||
# via -r requirements.in
|
||||
packaging==24.0 \
|
||||
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
|
||||
|
|
@ -600,9 +600,9 @@ regex==2024.5.15 \
|
|||
--hash=sha256:f8ec0c2fea1e886a19c3bee0cd19d862b3aa75dcdfb42ebe8ed30708df64687a \
|
||||
--hash=sha256:f9ebd0a36102fcad2f03696e8af4ae682793a5d30b46c647eaf280d6cfb32796
|
||||
# via mkdocs-material
|
||||
requests==2.32.2 \
|
||||
--hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \
|
||||
--hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
|
||||
requests==2.32.3 \
|
||||
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||
# via
|
||||
# importlib-metadata
|
||||
# importlib-resources
|
||||
|
|
@ -685,7 +685,7 @@ webencodings==0.5.1 \
|
|||
# via
|
||||
# cssselect2
|
||||
# tinycss2
|
||||
zipp==3.18.2 \
|
||||
--hash=sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059 \
|
||||
--hash=sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e
|
||||
zipp==3.19.2 \
|
||||
--hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \
|
||||
--hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c
|
||||
# via pytablewriter
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ Besides the HTTPS / SSL/TLS configuration, the following settings related to HTT
|
|||
| `AUTO_REDIRECT_HTTP_TO_HTTPS` | `yes` | When set to `yes`, will redirect every HTTP request to HTTPS only if BunkerWeb is configured with HTTPS. |
|
||||
| `SSL_PROTOCOLS` | `TLSv1.2 TLSv1.3` | List of supported SSL/TLS protocols when SSL is enabled. |
|
||||
| `HTTP2` | `yes` | When set to `yes`, will enable HTTP2 protocol support when using HTTPS. |
|
||||
| `HTTP3` | `yes` | When set to `yes`, will enable HTTP3 protocol support when using HTTPS. |
|
||||
| `HTTP3` | `no` | When set to `yes`, will enable HTTP3 protocol support when using HTTPS. |
|
||||
| `HTTP3_ALT_SVC_PORT` | `443` | HTTP3 alternate service port. This value will be used as part of the Alt-Svc header. |
|
||||
| `LISTEN_HTTP` | `yes` | When set to `no`, BunkerWeb will not listen for HTTP requests. Useful if you want HTTPS only for example. |
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@
|
|||
|
||||
Get support and more information :
|
||||
|
||||
- [Order professionnal support](https://panel.bunkerweb.io/?utm_source=doc&utm_campaign=self)
|
||||
- [Order professional support](https://panel.bunkerweb.io/?utm_source=doc&utm_campaign=self)
|
||||
- [Create an issue on GitHub](https://github.com/bunkerity/bunkerweb/issues)
|
||||
- [Join the BunkerWeb Discord server](https://discord.bunkerity.com)
|
||||
|
||||
|
|
@ -239,27 +239,40 @@
|
|||
|
||||
=== "SQLite"
|
||||
|
||||
1. **Remove the existing database file.**
|
||||
1. **Stop the Stack.**
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
2. **Remove the existing database file.**
|
||||
|
||||
```bash
|
||||
docker exec -u 0 -i <scheduler_container> rm -f /var/lib/bunkerweb/db.sqlite3
|
||||
```
|
||||
|
||||
2. **Restore the backup.**
|
||||
3. **Restore the backup.**
|
||||
|
||||
```bash
|
||||
docker exec -i -T <scheduler_container> sqlite3 /var/lib/bunkerweb/db.sqlite3 < /path/to/backup/directory/backup.sql
|
||||
```
|
||||
|
||||
=== "MySQL/MariaDB"
|
||||
|
||||
3. **Stop the Scheduler container.**
|
||||
4. **Fix permissions.**
|
||||
|
||||
```bash
|
||||
docker compose down <scheduler_container>
|
||||
docker exec -u 0 -i <scheduler_container> chown root:nginx /var/lib/bunkerweb/db.sqlite3
|
||||
docker exec -u 0 -i <scheduler_container> chmod 770 /var/lib/bunkerweb/db.sqlite3
|
||||
```
|
||||
|
||||
4. **Restore the backup.**
|
||||
=== "MySQL/MariaDB"
|
||||
|
||||
5. **Stop the Stack.**
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
6. **Restore the backup.**
|
||||
|
||||
```bash
|
||||
docker exec -e MYSQL_PWD=<your_password> -i -T <database_container> mysql -u <username> <database_name> < /path/to/backup/directory/backup.sql
|
||||
|
|
@ -267,25 +280,25 @@
|
|||
|
||||
=== "PostgreSQL"
|
||||
|
||||
5. **Stop the Scheduler container.**
|
||||
7. **Stop the Stack.**
|
||||
|
||||
```bash
|
||||
docker compose down <scheduler_container>
|
||||
docker compose down
|
||||
```
|
||||
|
||||
6. **Remove the existing database.**
|
||||
8. **Remove the existing database.**
|
||||
|
||||
```bash
|
||||
docker exec -i <database_container> dropdb -U <username> --force <database_name>
|
||||
```
|
||||
|
||||
7. **Recreate the database.**
|
||||
9. **Recreate the database.**
|
||||
|
||||
```bash
|
||||
docker exec -i <database_container> createdb -U <username> <database_name>
|
||||
```
|
||||
|
||||
8. **Restore the backup.**
|
||||
10. **Restore the backup.**
|
||||
|
||||
```bash
|
||||
docker exec -i -T <database_container> psql -U <username> -d <database_name> < /path/to/backup/directory/backup.sql
|
||||
|
|
@ -309,10 +322,9 @@
|
|||
...
|
||||
```
|
||||
|
||||
3. **Restart the containers**.
|
||||
3. **Start the containers**.
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
|
|
@ -321,8 +333,7 @@
|
|||
4. **Stop the services**.
|
||||
|
||||
```bash
|
||||
systemctl stop bunkerweb
|
||||
systemctl stop bunkerweb-ui
|
||||
systemctl stop bunkerweb bunkerweb-ui
|
||||
```
|
||||
|
||||
5. **Restore the backup**.
|
||||
|
|
@ -330,8 +341,10 @@
|
|||
=== "SQLite"
|
||||
|
||||
```bash
|
||||
rm -f /var/lib/bunkerweb/db.sqlite3
|
||||
sqlite3 /var/lib/bunkerweb/db.sqlite3 < /path/to/backup/directory/backup.sql
|
||||
sudo rm -f /var/lib/bunkerweb/db.sqlite3
|
||||
sudo sqlite3 /var/lib/bunkerweb/db.sqlite3 < /path/to/backup/directory/backup.sql
|
||||
sudo chown root:nginx /var/lib/bunkerweb/db.sqlite3
|
||||
sudo chmod 770 /var/lib/bunkerweb/db.sqlite3
|
||||
```
|
||||
|
||||
=== "MySQL/MariaDB"
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -8,8 +8,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ services:
|
|||
context: ../..
|
||||
dockerfile: ./src/bw/Dockerfile
|
||||
ports:
|
||||
- 80:8080
|
||||
- 443:8443
|
||||
- 80:8080/tcp
|
||||
- 443:8443/tcp
|
||||
- 443:8443/udp
|
||||
labels:
|
||||
- "bunkerweb.INSTANCE=yes"
|
||||
environment:
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ from contextlib import suppress
|
|||
from datetime import datetime
|
||||
from os import getenv
|
||||
from time import sleep
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from ConfigCaller import ConfigCaller # type: ignore
|
||||
from Database import Database # type: ignore
|
||||
from logger import setup_logger # type: ignore
|
||||
|
||||
|
||||
class Config(ConfigCaller):
|
||||
class Config:
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.__logger = setup_logger("Config", getenv("LOG_LEVEL", "INFO"))
|
||||
|
|
@ -40,25 +40,24 @@ class Config(ConfigCaller):
|
|||
self._settings.update(plugin["settings"])
|
||||
|
||||
def __get_full_env(self) -> dict:
|
||||
env_instances = {"SERVER_NAME": ""}
|
||||
for instance in self.__instances:
|
||||
for variable, value in instance["env"].items():
|
||||
env_instances[variable] = value
|
||||
env_services = {}
|
||||
config = {"SERVER_NAME": "", "MULTISITE": "yes"}
|
||||
for service in self.__services:
|
||||
server_name = service["SERVER_NAME"].split(" ")[0]
|
||||
if not server_name:
|
||||
continue
|
||||
for variable, value in service.items():
|
||||
env_services[f"{server_name}_{variable}"] = value
|
||||
env_instances["SERVER_NAME"] += f" {server_name}"
|
||||
env_instances["SERVER_NAME"] = env_instances["SERVER_NAME"].strip()
|
||||
return self._full_env(env_instances, env_services)
|
||||
if self._db.is_setting(variable, multisite=True):
|
||||
config[f"{server_name}_{variable}"] = value
|
||||
config["SERVER_NAME"] += f" {server_name}"
|
||||
config["SERVER_NAME"] = config["SERVER_NAME"].strip()
|
||||
return config
|
||||
|
||||
def update_needed(self, instances, services, configs={}) -> bool:
|
||||
def update_needed(self, instances: List[Dict[str, Any]], services: List[Dict[str, str]], configs: Optional[Dict[str, Dict[str, bytes]]] = None) -> bool:
|
||||
if instances != self.__instances:
|
||||
return True
|
||||
elif services != self.__services:
|
||||
return True
|
||||
elif configs != self.__configs:
|
||||
elif (configs or {}) != self.__configs:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
@ -76,15 +75,31 @@ class Config(ConfigCaller):
|
|||
):
|
||||
ready = True
|
||||
continue
|
||||
else:
|
||||
self.__logger.warning("Scheduler is already applying a configuration, retrying in 5 seconds ...")
|
||||
|
||||
def have_to_wait(self) -> bool:
|
||||
db_metadata = self._db.get_metadata()
|
||||
return isinstance(db_metadata, str) or any(
|
||||
v
|
||||
for k, v in db_metadata.items()
|
||||
if k in ("custom_configs_changed", "external_plugins_changed", "pro_plugins_changed", "config_changed", "instances_changed")
|
||||
)
|
||||
|
||||
def apply(
|
||||
self, instances: List[Dict[str, Any]], services: List[Dict[str, str]], configs: Optional[Dict[str, Dict[str, bytes]]] = None, first: bool = False
|
||||
) -> bool:
|
||||
success = True
|
||||
|
||||
err = self._try_database_readonly()
|
||||
if err:
|
||||
return False
|
||||
|
||||
while not self._db.is_initialized():
|
||||
self.__logger.warning("Database is not initialized, retrying in 5 seconds ...")
|
||||
sleep(5)
|
||||
|
||||
if not ready:
|
||||
raise Exception("Too many retries while waiting for scheduler to apply configuration...")
|
||||
self.wait_applying()
|
||||
|
||||
def apply(self, instances, services, configs={}, first=False) -> bool:
|
||||
success = True
|
||||
configs = configs or {}
|
||||
|
||||
changes = []
|
||||
if instances != self.__instances or first:
|
||||
|
|
@ -116,37 +131,10 @@ class Config(ConfigCaller):
|
|||
custom_configs.append(
|
||||
{
|
||||
"value": data,
|
||||
"exploded": [
|
||||
site,
|
||||
config_type,
|
||||
name.replace(".conf", ""),
|
||||
],
|
||||
"exploded": [site, config_type, name.replace(".conf", "")],
|
||||
}
|
||||
)
|
||||
|
||||
current_time = datetime.now()
|
||||
ready = False
|
||||
while not ready and (datetime.now() - current_time).seconds < 120:
|
||||
db_metadata = self._db.get_metadata()
|
||||
if isinstance(db_metadata, str) or not db_metadata["is_initialized"]:
|
||||
self.__logger.warning("Database is not initialized, retrying in 5s ...")
|
||||
sleep(5)
|
||||
continue
|
||||
ready = True
|
||||
|
||||
if not ready:
|
||||
self.__logger.error(f"Timeout while waiting for database to be initialized, ignoring changes ...\ndb data: {db_metadata}")
|
||||
return False
|
||||
|
||||
# wait until changes are applied
|
||||
ready = False
|
||||
with suppress(BaseException):
|
||||
self.wait_applying()
|
||||
ready = True
|
||||
|
||||
if not ready:
|
||||
self.__logger.warning("Timeout while waiting for scheduler to apply configuration, continuing anyway...")
|
||||
|
||||
# update instances in database
|
||||
if "instances" in changes:
|
||||
err = self._db.update_instances(self.__instances, "autoconf", changed=False)
|
||||
|
|
@ -154,11 +142,13 @@ class Config(ConfigCaller):
|
|||
self.__logger.error(f"Failed to update instances: {err}")
|
||||
|
||||
# save config to database
|
||||
changed_plugins = []
|
||||
if "config" in changes:
|
||||
err = self._db.save_config(self.__config, "autoconf", changed=False)
|
||||
if err:
|
||||
if isinstance(err, str):
|
||||
success = False
|
||||
self.__logger.error(f"Can't save config in database: {err}, config may not work as expected")
|
||||
changed_plugins = err
|
||||
|
||||
# save custom configs to database
|
||||
if "custom_configs" in changes:
|
||||
|
|
@ -168,10 +158,40 @@ class Config(ConfigCaller):
|
|||
self.__logger.error(f"Can't save autoconf custom configs in database: {err}, custom configs may not work as expected")
|
||||
|
||||
# update changes in db
|
||||
ret = self._db.checked_changes(changes, value=True)
|
||||
ret = self._db.checked_changes(changes, plugins_changes=changed_plugins, value=True)
|
||||
if ret:
|
||||
self.__logger.error(f"An error occurred when setting the changes to checked in the database : {ret}")
|
||||
|
||||
self.__logger.info("Successfully saved new configuration 🚀")
|
||||
|
||||
return success
|
||||
|
||||
def _try_database_readonly(self) -> bool:
|
||||
if not self._db.readonly:
|
||||
try:
|
||||
self._db.test_write()
|
||||
except BaseException:
|
||||
self._db.readonly = True
|
||||
return True
|
||||
|
||||
if self._db.database_uri and self._db.readonly:
|
||||
try:
|
||||
self._db.retry_connection(pool_timeout=1)
|
||||
self._db.retry_connection(log=False)
|
||||
self._db.readonly = False
|
||||
self.__logger.info("The database is no longer read-only, defaulting to read-write mode")
|
||||
except BaseException:
|
||||
try:
|
||||
self._db.retry_connection(readonly=True, pool_timeout=1)
|
||||
self._db.retry_connection(readonly=True, log=False)
|
||||
except BaseException:
|
||||
if self._db.database_uri_readonly:
|
||||
with suppress(BaseException):
|
||||
self._db.retry_connection(fallback=True, pool_timeout=1)
|
||||
self._db.retry_connection(fallback=True, log=False)
|
||||
self._db.readonly = True
|
||||
|
||||
if self._db.readonly:
|
||||
self.__logger.error("Database is in read-only mode, configuration will not be saved")
|
||||
|
||||
return self._db.readonly
|
||||
|
|
|
|||
|
|
@ -66,10 +66,6 @@ class Controller(Config):
|
|||
def _to_services(self, controller_service):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _get_static_services(self):
|
||||
pass
|
||||
|
||||
def _set_autoconf_load_db(self):
|
||||
if not self._loaded:
|
||||
ret = self._db.set_metadata({"autoconf_loaded": True})
|
||||
|
|
@ -79,10 +75,12 @@ class Controller(Config):
|
|||
self._loaded = True
|
||||
|
||||
def get_services(self):
|
||||
while not self._get_controller_services():
|
||||
sleep(1)
|
||||
|
||||
services = []
|
||||
for controller_service in self._get_controller_services():
|
||||
services.extend(self._to_services(controller_service))
|
||||
services.extend(self._get_static_services())
|
||||
return services
|
||||
|
||||
@abstractmethod
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from time import sleep
|
||||
from typing import Any, Dict, List
|
||||
from docker import DockerClient
|
||||
from re import compile as re_compile
|
||||
|
|
@ -22,54 +23,25 @@ class DockerController(Controller):
|
|||
return self.__client.containers.list(filters={"label": "bunkerweb.SERVER_NAME"})
|
||||
|
||||
def _to_instances(self, controller_instance) -> List[dict]:
|
||||
return [
|
||||
{
|
||||
"name": controller_instance.name,
|
||||
"hostname": controller_instance.name,
|
||||
"health": controller_instance.status == "running" and controller_instance.attrs["State"]["Health"]["Status"] == "healthy",
|
||||
"env": self._get_scheduler_env(),
|
||||
}
|
||||
]
|
||||
instance = {}
|
||||
instance["name"] = controller_instance.name
|
||||
instance["hostname"] = controller_instance.name
|
||||
instance["health"] = controller_instance.status == "running" and controller_instance.attrs["State"]["Health"]["Status"] == "healthy"
|
||||
instance["env"] = {}
|
||||
for env in controller_instance.attrs["Config"]["Env"]:
|
||||
variable = env.split("=")[0]
|
||||
value = env.replace(f"{variable}=", "", 1)
|
||||
instance["env"][variable] = value
|
||||
return [instance]
|
||||
|
||||
def _to_services(self, controller_service) -> List[dict]:
|
||||
service = {}
|
||||
for variable, value in controller_service.labels.items():
|
||||
if not variable.startswith("bunkerweb."):
|
||||
continue
|
||||
real_variable = variable.replace("bunkerweb.", "", 1)
|
||||
if not self._is_setting_context(real_variable, "multisite"):
|
||||
continue
|
||||
service[real_variable] = value
|
||||
service[variable.replace("bunkerweb.", "", 1)] = value
|
||||
return [service]
|
||||
|
||||
def _get_scheduler_env(self) -> Dict[str, str]:
|
||||
env = {}
|
||||
for instance in self.__client.containers.list(filters={"label": "bunkerweb.type=scheduler"}):
|
||||
if not instance.attrs or not instance.attrs.get("Config", {}).get("Env"):
|
||||
continue
|
||||
|
||||
for env_var in instance.attrs["Config"]["Env"]:
|
||||
variable = env_var.split("=")[0]
|
||||
value = env_var.replace(f"{variable}=", "", 1)
|
||||
env[variable] = value
|
||||
return env
|
||||
|
||||
def _get_static_services(self) -> List[dict]:
|
||||
services = []
|
||||
variables = self._get_scheduler_env()
|
||||
if "SERVER_NAME" in variables and variables["SERVER_NAME"].strip():
|
||||
for server_name in variables["SERVER_NAME"].strip().split(" "):
|
||||
if not server_name:
|
||||
continue
|
||||
service = {"SERVER_NAME": server_name}
|
||||
for variable, value in variables.items():
|
||||
prefix = variable.split("_")[0]
|
||||
real_variable = variable.replace(f"{prefix}_", "", 1)
|
||||
if prefix == server_name and self._is_setting_context(real_variable, "multisite"):
|
||||
service[real_variable] = value
|
||||
services.append(service)
|
||||
return services
|
||||
|
||||
def get_configs(self) -> Dict[str, Dict[str, Any]]:
|
||||
configs = {config_type: {} for config_type in self._supported_config_types}
|
||||
# get site configs from labels
|
||||
|
|
@ -112,21 +84,34 @@ class DockerController(Controller):
|
|||
def process_events(self):
|
||||
self._set_autoconf_load_db()
|
||||
for event in self.__client.events(decode=True, filters={"type": "container"}):
|
||||
applied = False
|
||||
try:
|
||||
if not self.__process_event(event):
|
||||
continue
|
||||
self.wait_applying()
|
||||
self._update_settings()
|
||||
self._instances = self.get_instances()
|
||||
self._services = self.get_services()
|
||||
self._configs = self.get_configs()
|
||||
if not self.update_needed(self._instances, self._services, configs=self._configs):
|
||||
continue
|
||||
self._logger.info("Caught Docker event, deploying new configuration ...")
|
||||
if not self.apply_config():
|
||||
self._logger.error("Error while deploying new configuration")
|
||||
else:
|
||||
self._logger.info("Successfully deployed new configuration 🚀")
|
||||
self._set_autoconf_load_db()
|
||||
to_apply = False
|
||||
while not applied:
|
||||
waiting = self.have_to_wait()
|
||||
self._update_settings()
|
||||
self._instances = self.get_instances()
|
||||
self._services = self.get_services()
|
||||
self._configs = self.get_configs()
|
||||
|
||||
if not to_apply and not self.update_needed(self._instances, self._services, configs=self._configs):
|
||||
applied = True
|
||||
continue
|
||||
|
||||
to_apply = True
|
||||
if waiting:
|
||||
sleep(1)
|
||||
continue
|
||||
|
||||
self._logger.info("Caught Docker event, deploying new configuration ...")
|
||||
if not self.apply_config():
|
||||
self._logger.error("Error while deploying new configuration")
|
||||
else:
|
||||
self._logger.info("Successfully deployed new configuration 🚀")
|
||||
|
||||
self._set_autoconf_load_db()
|
||||
applied = True
|
||||
except:
|
||||
self._logger.error(f"Exception while processing events :\n{format_exc()}")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
from contextlib import suppress
|
||||
from time import sleep
|
||||
from traceback import format_exc
|
||||
from typing import Dict, List
|
||||
from typing import List
|
||||
from kubernetes import client, config, watch
|
||||
from kubernetes.client.exceptions import ApiException
|
||||
from threading import Thread, Lock
|
||||
|
|
@ -39,6 +39,26 @@ class IngressController(Controller):
|
|||
health = True
|
||||
break
|
||||
instance["health"] = health
|
||||
instance["env"] = {}
|
||||
pod = None
|
||||
for container in controller_instance.spec.containers:
|
||||
if container.name == "bunkerweb":
|
||||
pod = container
|
||||
break
|
||||
if not pod:
|
||||
self._logger.warning(f"Missing container bunkerweb in pod {controller_instance.metadata.name}")
|
||||
else:
|
||||
for env in pod.env:
|
||||
instance["env"][env.name] = env.value or ""
|
||||
for controller_service in self._get_controller_services():
|
||||
if controller_service.metadata.annotations:
|
||||
for (
|
||||
annotation,
|
||||
value,
|
||||
) in controller_service.metadata.annotations.items():
|
||||
if not annotation.startswith("bunkerweb.io/"):
|
||||
continue
|
||||
instance["env"][annotation.replace("bunkerweb.io/", "", 1)] = value
|
||||
return [instance]
|
||||
|
||||
def _get_controller_services(self) -> list:
|
||||
|
|
@ -120,9 +140,7 @@ class IngressController(Controller):
|
|||
server_name = service["SERVER_NAME"].strip().split(" ")[0]
|
||||
if not variable.startswith(f"{server_name}_"):
|
||||
continue
|
||||
variable = variable.replace(f"{server_name}_", "", 1)
|
||||
if self._is_setting_context(variable, "multisite"):
|
||||
service[variable] = value
|
||||
service[variable.replace(f"{server_name}_", "", 1)] = value
|
||||
|
||||
# parse tls
|
||||
if controller_service.spec.tls:
|
||||
|
|
@ -156,37 +174,6 @@ class IngressController(Controller):
|
|||
service["CUSTOM_SSL_KEY_DATA"] = secret_tls.data["tls.key"]
|
||||
return services
|
||||
|
||||
def _get_scheduler_env(self) -> Dict[str, str]:
|
||||
variables = {}
|
||||
for instance in self.__corev1.list_pod_for_all_namespaces(watch=False).items:
|
||||
if not instance.metadata.annotations or "bunkerweb.io/SCHEDULER" not in instance.metadata.annotations:
|
||||
continue
|
||||
|
||||
pod = None
|
||||
for container in instance.spec.containers:
|
||||
if container.name == "bunkerweb-scheduler":
|
||||
pod = container
|
||||
break
|
||||
if not pod:
|
||||
continue
|
||||
|
||||
variables = {env.name: env.value or "" for env in pod.env}
|
||||
return variables
|
||||
|
||||
def _get_static_services(self) -> List[dict]:
|
||||
services = []
|
||||
variables = self._get_scheduler_env()
|
||||
if "SERVER_NAME" in variables and variables["SERVER_NAME"].strip():
|
||||
for server_name in variables["SERVER_NAME"].strip().split(" "):
|
||||
service = {"SERVER_NAME": server_name}
|
||||
for variable, value in variables.items():
|
||||
prefix = variable.split("_")[0]
|
||||
real_variable = variable.replace(f"{prefix}_", "", 1)
|
||||
if prefix == server_name and self._is_setting_context(real_variable, "multisite"):
|
||||
service[real_variable] = value
|
||||
services.append(service)
|
||||
return services
|
||||
|
||||
def get_configs(self) -> dict:
|
||||
configs = {config_type: {} for config_type in self._supported_config_types}
|
||||
for configmap in self.__corev1.list_config_map_for_all_namespaces(watch=False).items:
|
||||
|
|
@ -254,21 +241,37 @@ class IngressController(Controller):
|
|||
while True:
|
||||
locked = False
|
||||
error = False
|
||||
applied = False
|
||||
try:
|
||||
for event in w.stream(what):
|
||||
with self.__internal_lock:
|
||||
locked = True
|
||||
if not self.__process_event(event):
|
||||
locked = False
|
||||
continue
|
||||
self.wait_applying()
|
||||
applied = False
|
||||
self.__internal_lock.acquire()
|
||||
locked = True
|
||||
if not self.__process_event(event):
|
||||
self.__internal_lock.release()
|
||||
locked = False
|
||||
continue
|
||||
|
||||
to_apply = False
|
||||
while not applied:
|
||||
waiting = self.have_to_wait()
|
||||
self._update_settings()
|
||||
self._instances = self.get_instances()
|
||||
self._services = self.get_services()
|
||||
self._configs = self.get_configs()
|
||||
if not self.update_needed(self._instances, self._services, configs=self._configs):
|
||||
locked = False
|
||||
|
||||
if not to_apply and not self.update_needed(self._instances, self._services, configs=self._configs):
|
||||
if locked:
|
||||
self.__internal_lock.release()
|
||||
locked = False
|
||||
applied = True
|
||||
continue
|
||||
|
||||
to_apply = True
|
||||
if waiting:
|
||||
sleep(1)
|
||||
continue
|
||||
|
||||
self._logger.info(f"Caught kubernetes event ({watch_type}), deploying new configuration ...")
|
||||
try:
|
||||
ret = self.apply_config()
|
||||
|
|
@ -276,10 +279,15 @@ class IngressController(Controller):
|
|||
self._logger.error("Error while deploying new configuration ...")
|
||||
else:
|
||||
self._logger.info("Successfully deployed new configuration 🚀")
|
||||
|
||||
self._set_autoconf_load_db()
|
||||
except:
|
||||
self._logger.error(f"Exception while deploying new configuration :\n{format_exc()}")
|
||||
locked = False
|
||||
applied = True
|
||||
|
||||
if locked:
|
||||
self.__internal_lock.release()
|
||||
locked = False
|
||||
except ApiException as e:
|
||||
if e.status != 410:
|
||||
self._logger.error(f"API exception while reading k8s event (type = {watch_type}) :\n{format_exc()}")
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@ class SwarmController(Controller):
|
|||
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"]:
|
||||
variable = env.split("=")[0]
|
||||
value = env.replace(f"{variable}=", "", 1)
|
||||
instance_env[variable] = value
|
||||
|
||||
for task in controller_instance.tasks():
|
||||
if task["DesiredState"] != "running":
|
||||
continue
|
||||
|
|
@ -51,41 +57,9 @@ class SwarmController(Controller):
|
|||
for variable, value in controller_service.attrs["Spec"]["Labels"].items():
|
||||
if not variable.startswith("bunkerweb."):
|
||||
continue
|
||||
real_variable = variable.replace("bunkerweb.", "", 1)
|
||||
if not self._is_setting_context(real_variable, "multisite"):
|
||||
continue
|
||||
service[real_variable] = value
|
||||
service[variable.replace("bunkerweb.", "", 1)] = value
|
||||
return [service]
|
||||
|
||||
def _get_scheduler_env(self) -> Dict[str, str]:
|
||||
env = {}
|
||||
for instance in self.__client.services.list(filters={"label": "bunkerweb.type=scheduler"}):
|
||||
if not instance.attrs or not instance.attrs.get("Spec", {}).get("TaskTemplate", {}).get("ContainerSpec", {}).get("Env"):
|
||||
continue
|
||||
|
||||
for env in instance.attrs["Spec"]["TaskTemplate"]["ContainerSpec"]["Env"]:
|
||||
variable = env.split("=")[0]
|
||||
value = env.replace(f"{variable}=", "", 1)
|
||||
env[variable] = value
|
||||
return env
|
||||
|
||||
def _get_static_services(self) -> List[dict]:
|
||||
services = []
|
||||
variables = self._get_scheduler_env()
|
||||
if "SERVER_NAME" in variables and variables["SERVER_NAME"].strip():
|
||||
for server_name in variables["SERVER_NAME"].strip().split(" "):
|
||||
if not server_name:
|
||||
continue
|
||||
service = {}
|
||||
service["SERVER_NAME"] = server_name
|
||||
for variable, value in variables.items():
|
||||
prefix = variable.split("_")[0]
|
||||
real_variable = variable.replace(f"{prefix}_", "", 1)
|
||||
if prefix == server_name and self._is_setting_context(real_variable, "multisite"):
|
||||
service[real_variable] = value
|
||||
services.append(service)
|
||||
return services
|
||||
|
||||
def get_configs(self) -> Dict[str, Dict[str, Any]]:
|
||||
self.__swarm_configs = []
|
||||
configs = {}
|
||||
|
|
@ -148,31 +122,53 @@ class SwarmController(Controller):
|
|||
while True:
|
||||
locked = False
|
||||
error = False
|
||||
applied = False
|
||||
try:
|
||||
for event in self.__client.events(decode=True, filters={"type": event_type}):
|
||||
with self.__internal_lock:
|
||||
locked = True
|
||||
if not self.__process_event(event):
|
||||
locked = False
|
||||
continue
|
||||
try:
|
||||
self.wait_applying()
|
||||
applied = False
|
||||
self.__internal_lock.acquire()
|
||||
locked = True
|
||||
if not self.__process_event(event):
|
||||
self.__internal_lock.release()
|
||||
locked = False
|
||||
continue
|
||||
|
||||
try:
|
||||
to_apply = False
|
||||
while not applied:
|
||||
waiting = self.have_to_wait()
|
||||
self._update_settings()
|
||||
self._instances = self.get_instances()
|
||||
self._services = self.get_services()
|
||||
self._configs = self.get_configs()
|
||||
if not self.update_needed(self._instances, self._services, configs=self._configs):
|
||||
locked = False
|
||||
|
||||
if not to_apply and not self.update_needed(self._instances, self._services, configs=self._configs):
|
||||
if locked:
|
||||
self.__internal_lock.release()
|
||||
locked = False
|
||||
applied = True
|
||||
continue
|
||||
|
||||
to_apply = True
|
||||
if waiting:
|
||||
sleep(1)
|
||||
continue
|
||||
|
||||
self._logger.info(f"Caught Swarm event ({event_type}), deploying new configuration ...")
|
||||
if not self.apply_config():
|
||||
self._logger.error("Error while deploying new configuration")
|
||||
else:
|
||||
self._logger.info("Successfully deployed new configuration 🚀")
|
||||
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()}")
|
||||
locked = False
|
||||
applied = True
|
||||
except BaseException:
|
||||
self._logger.error(f"Exception while processing Swarm event ({event_type}) :\n{format_exc()}")
|
||||
|
||||
if locked:
|
||||
self.__internal_lock.release()
|
||||
locked = False
|
||||
except:
|
||||
self._logger.error(f"Exception while reading Swarm event ({event_type}) :\n{format_exc()}")
|
||||
error = True
|
||||
|
|
|
|||
|
|
@ -59,11 +59,7 @@ try:
|
|||
LOGGER.info(f"Instance #{i} : {instance['name']}")
|
||||
i += 1
|
||||
|
||||
# Run first configuration
|
||||
ret = controller.apply_config()
|
||||
if not ret:
|
||||
LOGGER.error("Error while applying initial configuration")
|
||||
_exit(1)
|
||||
controller.wait_applying(True)
|
||||
|
||||
# Process events
|
||||
Path(sep, "var", "tmp", "bunkerweb", "autoconf.healthy").write_text("ok")
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
docker==7.1.0
|
||||
kubernetes==29.0.0
|
||||
kubernetes==30.1.0
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ cachetools==5.3.3 \
|
|||
--hash=sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945 \
|
||||
--hash=sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105
|
||||
# via google-auth
|
||||
certifi==2024.2.2 \
|
||||
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
||||
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
||||
certifi==2024.6.2 \
|
||||
--hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \
|
||||
--hash=sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56
|
||||
# via
|
||||
# kubernetes
|
||||
# requests
|
||||
|
|
@ -110,17 +110,17 @@ docker==7.1.0 \
|
|||
--hash=sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c \
|
||||
--hash=sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0
|
||||
# via -r requirements.in
|
||||
google-auth==2.29.0 \
|
||||
--hash=sha256:672dff332d073227550ffc7457868ac4218d6c500b155fe6cc17d2b13602c360 \
|
||||
--hash=sha256:d452ad095688cd52bae0ad6fafe027f6a6d6f560e810fec20914e17a09526415
|
||||
google-auth==2.30.0 \
|
||||
--hash=sha256:8df7da660f62757388b8a7f249df13549b3373f24388cb5d2f1dd91cc18180b5 \
|
||||
--hash=sha256:ab630a1320f6720909ad76a7dbdb6841cdf5c66b328d690027e4867bdfb16688
|
||||
# via kubernetes
|
||||
idna==3.7 \
|
||||
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
|
||||
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
|
||||
# via requests
|
||||
kubernetes==29.0.0 \
|
||||
--hash=sha256:ab8cb0e0576ccdfb71886366efb102c6a20f268d817be065ce7f9909c631e43e \
|
||||
--hash=sha256:c4812e227ae74d07d53c88293e564e54b850452715a59a927e7e1bc6b9a60459
|
||||
kubernetes==30.1.0 \
|
||||
--hash=sha256:41e4c77af9f28e7a6c314e3bd06a8c6229ddd787cad684e0ab9f69b498e98ebc \
|
||||
--hash=sha256:e212e8b7579031dd2e512168b617373bc1e03888d41ac4e04039240a292d478d
|
||||
# via -r requirements.in
|
||||
oauthlib==3.2.2 \
|
||||
--hash=sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca \
|
||||
|
|
@ -195,9 +195,9 @@ pyyaml==6.0.1 \
|
|||
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
|
||||
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
|
||||
# via kubernetes
|
||||
requests==2.32.2 \
|
||||
--hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \
|
||||
--hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
|
||||
requests==2.32.3 \
|
||||
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||
# via
|
||||
# docker
|
||||
# kubernetes
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
FROM nginx:1.26.0-alpine-slim@sha256:be13c98f606eef87521627d5c794a98ac1e5a8fcb085e75acdc0c9d66a28666c AS builder
|
||||
FROM nginx:1.26.1-alpine-slim@sha256:3df0d85b2e46d4195e7436c22694ef65944c48624282292cadfbf58ee0ad34ce AS builder
|
||||
|
||||
# Install temporary requirements for the dependencies
|
||||
RUN apk add --no-cache bash autoconf libtool automake geoip-dev g++ gcc curl-dev libxml2-dev pcre-dev make linux-headers musl-dev gd-dev gnupg brotli-dev openssl-dev patch readline-dev yajl yajl-dev yajl-tools py3-pip
|
||||
|
|
@ -42,7 +42,7 @@ COPY src/common/utils utils
|
|||
COPY src/VERSION VERSION
|
||||
COPY misc/*.ascii misc/
|
||||
|
||||
FROM nginx:1.26.0-alpine-slim@sha256:be13c98f606eef87521627d5c794a98ac1e5a8fcb085e75acdc0c9d66a28666c
|
||||
FROM nginx:1.26.1-alpine-slim@sha256:3df0d85b2e46d4195e7436c22694ef65944c48624282292cadfbf58ee0ad34ce
|
||||
|
||||
# Set default umask to prevent huge recursive chmod increasing the final image size
|
||||
RUN umask 027
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -20,6 +20,7 @@ for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in ((
|
|||
|
||||
from API import API # type: ignore
|
||||
from ApiCaller import ApiCaller # type: ignore
|
||||
from common_utils import get_integration # type: ignore
|
||||
from logger import setup_logger # type: ignore
|
||||
|
||||
|
||||
|
|
@ -71,6 +72,7 @@ class CLI(ApiCaller):
|
|||
|
||||
assert isinstance(self.__variables, dict), "Failed to get variables from database"
|
||||
|
||||
self.__integration = get_integration()
|
||||
self.__use_redis = self.__get_variable("USE_REDIS", "no") == "yes"
|
||||
self.__redis = None
|
||||
if self.__use_redis:
|
||||
|
|
@ -113,7 +115,7 @@ class CLI(ApiCaller):
|
|||
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]
|
||||
sentinel_hosts = [host.split(":") if ":" in host else (host, "26379") for host in sentinel_hosts.split(" ") if host]
|
||||
|
||||
if sentinel_hosts:
|
||||
sentinel_username = self.__get_variable("REDIS_SENTINEL_USERNAME", None) or None
|
||||
|
|
@ -178,8 +180,17 @@ class CLI(ApiCaller):
|
|||
self.__logger.error("USE_REDIS is set to yes but REDIS_HOST or REDIS_SENTINEL_HOSTS is not set, disabling redis")
|
||||
self.__use_redis = False
|
||||
|
||||
for db_instance in self.__db.get_instances():
|
||||
self.apis.append(API(db_instance["hostname"], db_instance["port"], db_instance["server_name"]))
|
||||
if Path(sep, "usr", "sbin", "nginx").exists() or self.__integration == "Linux":
|
||||
return super().__init__(
|
||||
[
|
||||
API(
|
||||
f"http://127.0.0.1:{self.__get_variable('API_HTTP_PORT', '5000')}",
|
||||
host=self.__get_variable("API_SERVER_NAME", "bwapi"),
|
||||
)
|
||||
]
|
||||
)
|
||||
super().__init__()
|
||||
self.auto_setup(self.__integration)
|
||||
|
||||
def __get_variable(self, variable: str, default: Optional[Any] = None) -> Optional[str]:
|
||||
return getenv(variable, self.__variables.get(variable, default))
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ init_by_lua_block {
|
|||
if not ok then
|
||||
logger:log(ERR, plugin)
|
||||
else
|
||||
local ok, err = datastore:set("plugin_" .. plugin.id, plugin, true)
|
||||
local ok, err = datastore:set("plugin_" .. plugin.id, plugin, nil, true)
|
||||
if not ok then
|
||||
logger:log(ERR, "can't save " .. plugin.id .. " into datastore : " .. err)
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
server {
|
||||
# server name (vhost)
|
||||
server_name '{{ SERVER_NAME.split(" ")[0] }}';
|
||||
|
||||
# listen
|
||||
{% if LISTEN_STREAM == "yes" +%}
|
||||
|
|
@ -18,7 +20,6 @@ server {
|
|||
set $reason '';
|
||||
set $reason_data '';
|
||||
set $ctx_ref '';
|
||||
set $server_name '{{ SERVER_NAME.split(" ")[0] }}';
|
||||
|
||||
# include config files
|
||||
include {{ NGINX_PREFIX }}server-stream/*.conf;
|
||||
|
|
|
|||
|
|
@ -4,15 +4,15 @@ ssl_protocols {{ SSL_PROTOCOLS }};
|
|||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_tickets off;
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:MozSSL:10m;
|
||||
ssl_session_cache shared:MozSSLStream:10m;
|
||||
{% if "TLSv1.2" in SSL_PROTOCOLS +%}
|
||||
ssl_dhparam /etc/nginx/dhparam;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
|
||||
{% endif %}
|
||||
|
||||
listen 0.0.0.0:{{ LISTEN_STREAM_PORT_SSL }} ssl {% if USE_UDP == "yes" %} udp {% endif %}{% if USE_PROXY_PROTOCOL == "yes" %} proxy_protocol {% endif %};
|
||||
listen 0.0.0.0:{{ LISTEN_STREAM_PORT_SSL }} ssl {% if USE_PROXY_PROTOCOL == "yes" %} proxy_protocol {% endif %};
|
||||
{% if USE_IPV6 == "yes" +%}
|
||||
listen [::]:{{ LISTEN_STREAM_PORT_SSL }} ssl {% if USE_UDP == "yes" %} udp {% endif %}{% if USE_PROXY_PROTOCOL == "yes" %} proxy_protocol {% endif %};
|
||||
listen [::]:{{ LISTEN_STREAM_PORT_SSL }} ssl {% if USE_PROXY_PROTOCOL == "yes" %} proxy_protocol {% endif %};
|
||||
{% endif %}
|
||||
|
||||
ssl_certificate_by_lua_block {
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ resolver_timeout 30s;
|
|||
tcp_nodelay on;
|
||||
|
||||
# lua path and dicts
|
||||
lua_package_path "/usr/share/bunkerweb/lua/?.lua;/usr/share/bunkerweb/core/?.lua;/etc/bunkerweb/plugins/?.lua;/etc/bunkerweb/pro/plugins/?.lua;/usr/share/bunkerweb/deps/lib/lua/?.lua;;";
|
||||
lua_package_path "/usr/share/bunkerweb/lua/?.lua;/usr/share/bunkerweb/core/?.lua;/etc/bunkerweb/plugins/?.lua;/etc/bunkerweb/pro/plugins/?.lua;/usr/share/bunkerweb/deps/lib/lua/?.lua;/usr/share/bunkerweb/deps/lib/lua/?/init.lua;;";
|
||||
lua_package_cpath "/usr/share/bunkerweb/deps/lib/?.so;/usr/share/bunkerweb/deps/lib/lua/?.so;;";
|
||||
lua_ssl_trusted_certificate "/usr/share/bunkerweb/misc/root-ca.pem";
|
||||
lua_ssl_verify_depth 2;
|
||||
|
|
|
|||
|
|
@ -45,49 +45,57 @@ def backup_database(current_time: datetime, db: Database = None, backup_dir: Pat
|
|||
database: Literal["sqlite", "mariadb", "mysql", "postgresql"] = db.database_uri.split(":")[0].split("+")[0] # type: ignore
|
||||
backup_file = backup_dir.joinpath(f"backup-{database}-{current_time.strftime('%Y-%m-%d_%H-%M-%S')}.zip")
|
||||
LOGGER.debug(f"Backup file path: {backup_file}")
|
||||
stderr = "Table 'db.test_"
|
||||
current_time = datetime.now()
|
||||
|
||||
if database == "sqlite":
|
||||
match = DB_STRING_RX.search(db.database_uri)
|
||||
if not match:
|
||||
LOGGER.error(f"Invalid database string provided: {db.database_uri}, skipping backup ...")
|
||||
while "Table 'db.test_" in stderr and (datetime.now() - current_time).total_seconds() < 10:
|
||||
if database == "sqlite":
|
||||
match = DB_STRING_RX.search(db.database_uri)
|
||||
if not match:
|
||||
LOGGER.error(f"Invalid database string provided: {db.database_uri}, skipping backup ...")
|
||||
sys_exit(1)
|
||||
|
||||
db_path = Path(match.group("path"))
|
||||
|
||||
LOGGER.info("Creating a backup for the SQLite database ...")
|
||||
|
||||
proc = run(["sqlite3", db_path.as_posix(), ".dump"], stdout=PIPE, stderr=PIPE)
|
||||
else:
|
||||
db_host = db.database_uri.rsplit("@", 1)[1].split("/")[0].split(":")
|
||||
db_port = None
|
||||
if len(db_host) == 1:
|
||||
db_host = db_host[0]
|
||||
else:
|
||||
db_host, db_port = db_host
|
||||
|
||||
db_user = db.database_uri.split("://")[1].split(":")[0]
|
||||
db_password = db.database_uri.split("://")[1].split(":")[1].rsplit("@", 1)[0]
|
||||
db_database_name = db.database_uri.split("/")[-1].split("?")[0]
|
||||
|
||||
if database in ("mariadb", "mysql"):
|
||||
LOGGER.info("Creating a backup for the MariaDB/MySQL database ...")
|
||||
|
||||
cmd = ["mysqldump", "-h", db_host, "-u", db_user, db_database_name]
|
||||
if db_port:
|
||||
cmd.extend(["-P", db_port])
|
||||
|
||||
proc = run(cmd, stdout=PIPE, stderr=PIPE, env=environ | {"MYSQL_PWD": db_password})
|
||||
elif database == "postgresql":
|
||||
LOGGER.info("Creating a backup for the PostgreSQL database ...")
|
||||
|
||||
cmd = ["pg_dump", "-h", db_host, "-U", db_user, db_database_name, "-w"]
|
||||
if db_port:
|
||||
cmd.extend(["-p", db_port])
|
||||
|
||||
proc = run(cmd, stdout=PIPE, stderr=PIPE, env=environ | {"PGPASSWORD": db_password})
|
||||
|
||||
stderr = proc.stderr.decode()
|
||||
if "Table 'db.test_" not in stderr and proc.returncode != 0:
|
||||
LOGGER.error(f"Failed to dump the database: {stderr}")
|
||||
sys_exit(1)
|
||||
|
||||
db_path = Path(match.group("path"))
|
||||
|
||||
LOGGER.info("Creating a backup for the SQLite database ...")
|
||||
|
||||
proc = run(["sqlite3", db_path.as_posix(), ".dump"], stdout=PIPE, stderr=PIPE)
|
||||
else:
|
||||
db_host = db.database_uri.rsplit("@", 1)[1].split("/")[0].split(":")
|
||||
db_port = None
|
||||
if len(db_host) == 1:
|
||||
db_host = db_host[0]
|
||||
else:
|
||||
db_host, db_port = db_host
|
||||
|
||||
db_user = db.database_uri.split("://")[1].split(":")[0]
|
||||
db_password = db.database_uri.split("://")[1].split(":")[1].rsplit("@", 1)[0]
|
||||
db_database_name = db.database_uri.split("/")[-1]
|
||||
|
||||
if database in ("mariadb", "mysql"):
|
||||
LOGGER.info("Creating a backup for the MariaDB/MySQL database ...")
|
||||
|
||||
cmd = ["mysqldump", "-h", db_host, "-u", db_user, db_database_name]
|
||||
if db_port:
|
||||
cmd.extend(["-P", db_port])
|
||||
|
||||
proc = run(cmd, stdout=PIPE, stderr=PIPE, env=environ | {"MYSQL_PWD": db_password})
|
||||
elif database == "postgresql":
|
||||
LOGGER.info("Creating a backup for the PostgreSQL database ...")
|
||||
|
||||
cmd = ["pg_dump", "-h", db_host, "-U", db_user, db_database_name, "-w"]
|
||||
if db_port:
|
||||
cmd.extend(["-p", db_port])
|
||||
|
||||
proc = run(cmd, stdout=PIPE, stderr=PIPE, env=environ | {"PGPASSWORD": db_password})
|
||||
|
||||
if proc.returncode != 0:
|
||||
LOGGER.error(f"Failed to dump the database: {proc.stderr.decode()}")
|
||||
if (datetime.now() - current_time).total_seconds() >= 10:
|
||||
LOGGER.error("Failed to dump the database: Timeout reached")
|
||||
sys_exit(1)
|
||||
|
||||
with ZipFile(backup_file, "w", compression=ZIP_DEFLATED) as zipf:
|
||||
|
|
@ -142,7 +150,7 @@ def restore_database(backup_file: Path, db: Database = None) -> Database:
|
|||
|
||||
db_user = db.database_uri.split("://")[1].split(":")[0]
|
||||
db_password = db.database_uri.split("://")[1].split(":")[1].rsplit("@", 1)[0]
|
||||
db_database_name = db.database_uri.split("/")[-1]
|
||||
db_database_name = db.database_uri.split("/")[-1].split("?")[0]
|
||||
|
||||
if database in ("mariadb", "mysql"):
|
||||
LOGGER.info("Restoring the MariaDB/MySQL database ...")
|
||||
|
|
@ -179,7 +187,7 @@ def restore_database(backup_file: Path, db: Database = None) -> Database:
|
|||
LOGGER.error(f"Failed to restore the database: {proc.stderr.decode()}")
|
||||
sys_exit(1)
|
||||
|
||||
err = db.checked_changes(value=True)
|
||||
err = db.checked_changes(plugins_changes="all", value=True)
|
||||
if err:
|
||||
LOGGER.error(f"Error while applying changes to the database: {err}, you may need to reload the application")
|
||||
|
||||
|
|
|
|||
87
src/common/core/jobs/jobs/update-check.py
Normal file
87
src/common/core/jobs/jobs/update-check.py
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from os import getenv, sep
|
||||
from os.path import join
|
||||
from sys import exit as sys_exit, path as sys_path
|
||||
from traceback import format_exc
|
||||
|
||||
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",))]:
|
||||
if deps_path not in sys_path:
|
||||
sys_path.append(deps_path)
|
||||
|
||||
from requests import get
|
||||
|
||||
from common_utils import get_version # type: ignore
|
||||
from logger import setup_logger # type: ignore
|
||||
|
||||
LOGGER = setup_logger("UPDATE-CHECK", getenv("LOG_LEVEL", "INFO"))
|
||||
status = 0
|
||||
|
||||
try:
|
||||
|
||||
def get_latest_stable_release():
|
||||
response = get("https://api.github.com/repos/bunkerity/bunkerweb/releases", headers={"User-Agent": "BunkerWeb"}, timeout=3)
|
||||
response.raise_for_status()
|
||||
releases = response.json()
|
||||
|
||||
for release in releases:
|
||||
if not release["prerelease"]:
|
||||
return release
|
||||
return None
|
||||
|
||||
latest_release = get_latest_stable_release()
|
||||
|
||||
if not latest_release:
|
||||
status = 1
|
||||
LOGGER.error("Failed to fetch latest release information")
|
||||
sys_exit(status)
|
||||
|
||||
current_version = get_version()
|
||||
latest_version = latest_release["tag_name"].removeprefix("v")
|
||||
|
||||
if current_version != latest_version:
|
||||
# Version details
|
||||
latest_version_text = f"\033[1;92m{latest_version}\033[0m"
|
||||
current_version_text = f"\033[1;93m{current_version}\033[0m"
|
||||
release_notes_url = f"https://github.com/bunkerity/bunkerweb/releases/v{latest_version}"
|
||||
release_notes_url_text = f"\033[4;94m{release_notes_url}\033[0m"
|
||||
|
||||
# Centering based on the longest line length
|
||||
alert_message = "🚨 A NEW VERSION OF BUNKERWEB IS AVAILABLE! 🚨"
|
||||
latest_version_line = f"Latest Version: {latest_version_text}"
|
||||
current_version_line = f"Current Version: {current_version_text}"
|
||||
release_notes_url_line = f"Release Notes: {release_notes_url_text}"
|
||||
|
||||
# Determine the longest line length
|
||||
longest_line_length = max(
|
||||
len(alert_message),
|
||||
len(latest_version_line),
|
||||
len(current_version_line),
|
||||
len(release_notes_url_line),
|
||||
)
|
||||
|
||||
# Centering the lines within the box width
|
||||
alert_message_padded = alert_message.center(longest_line_length - 13)
|
||||
latest_version_padded = latest_version_line.center(longest_line_length)
|
||||
current_version_padded = current_version_line.center(longest_line_length)
|
||||
LOGGER.warning(
|
||||
(
|
||||
f"\n\033[1;91m{'*' * (longest_line_length - 5)}\n"
|
||||
f"\033[1;91m*{' ' * (longest_line_length - 7)}*\n"
|
||||
f"\033[1;91m* \033[1;97m{alert_message_padded}\033[0m \033[0;91m*\n"
|
||||
f"\033[1;91m*{' ' * (longest_line_length - 7)}*\n"
|
||||
f"\033[1;91m* \033[1;97m{latest_version_padded}\033[0;91m *\n"
|
||||
f"\033[1;91m* \033[1;97m{current_version_padded}\033[0;91m *\n"
|
||||
f"\033[1;91m*{' ' * (longest_line_length - 7)}*\n"
|
||||
f"\033[1;91m* \033[1;97m{release_notes_url_line}\033[0;91m *\n"
|
||||
f"\033[1;91m*{' ' * (longest_line_length - 7)}*\n"
|
||||
f"\033[1;91m{'*' * (longest_line_length - 5)}\033[0m"
|
||||
)
|
||||
)
|
||||
else:
|
||||
LOGGER.info(f"Latest version is already installed: {current_version}")
|
||||
except:
|
||||
status = 2
|
||||
LOGGER.error(f"Exception while running update-check.py :\n{format_exc()}")
|
||||
|
||||
sys_exit(status)
|
||||
|
|
@ -19,9 +19,9 @@
|
|||
"reload": true
|
||||
},
|
||||
{
|
||||
"name": "download-plugins",
|
||||
"file": "download-plugins.py",
|
||||
"every": "once",
|
||||
"name": "update-check",
|
||||
"file": "update-check.py",
|
||||
"every": "day",
|
||||
"reload": false
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ try:
|
|||
# Check if we're using let's encrypt
|
||||
use_letsencrypt = False
|
||||
is_multisite = getenv("MULTISITE", "no") == "yes"
|
||||
all_domains = getenv("SERVER_NAME", "")
|
||||
all_domains = getenv("SERVER_NAME", "").lower()
|
||||
server_names = all_domains.split(" ")
|
||||
|
||||
if getenv("AUTO_LETS_ENCRYPT", "no") == "yes":
|
||||
|
|
@ -88,7 +88,7 @@ try:
|
|||
if not use_letsencrypt:
|
||||
LOGGER.info("Let's Encrypt is not activated, skipping generation...")
|
||||
sys_exit(0)
|
||||
elif not getenv("SERVER_NAME"):
|
||||
elif not all_domains:
|
||||
LOGGER.warning("There are no server names, skipping generation...")
|
||||
sys_exit(0)
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ try:
|
|||
for first_server in server_names:
|
||||
if not first_server or getenv(f"{first_server}_AUTO_LETS_ENCRYPT", getenv("AUTO_LETS_ENCRYPT", "no")) != "yes":
|
||||
continue
|
||||
domains_server_names[first_server] = getenv(f"{first_server}_SERVER_NAME", first_server)
|
||||
domains_server_names[first_server] = getenv(f"{first_server}_SERVER_NAME", first_server).lower()
|
||||
# Singlesite case
|
||||
else:
|
||||
domains_server_names = {server_names[0]: all_domains}
|
||||
|
|
@ -172,7 +172,7 @@ try:
|
|||
if getenv("LETS_ENCRYPT_CLEAR_OLD_CERTS", "no") == "yes":
|
||||
LOGGER.info("Clear old certificates is activated, removing old / no longer used certificates...")
|
||||
for elem in chain(DATA_PATH.glob("archive/*"), DATA_PATH.glob("live/*"), DATA_PATH.glob("renewal/*")):
|
||||
if elem.name.replace(".conf", "") not in generated_domains:
|
||||
if elem.name.replace(".conf", "") not in generated_domains and elem.name != "README":
|
||||
LOGGER.warning(f"Removing old certificate {elem}")
|
||||
if elem.is_dir():
|
||||
rmtree(elem, ignore_errors=True)
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from os import getenv, sep
|
||||
from os.path import basename, join
|
||||
from sys import exit as sys_exit, path as sys_path
|
||||
from traceback import format_exc
|
||||
|
||||
for deps_path in [join(sep, "usr", "share", "bunkerweb", *paths) for paths in (("deps", "python"), ("utils",))]:
|
||||
if deps_path not in sys_path:
|
||||
sys_path.append(deps_path)
|
||||
|
||||
from requests import get
|
||||
|
||||
from common_utils import get_version # type: ignore
|
||||
from logger import setup_logger # type: ignore
|
||||
|
||||
LOGGER = setup_logger("UPDATE-CHECK", getenv("LOG_LEVEL", "INFO"))
|
||||
status = 0
|
||||
|
||||
try:
|
||||
current_version = f"v{get_version().strip()}"
|
||||
|
||||
response = get("https://github.com/bunkerity/bunkerweb/releases/latest", headers={"User-Agent": "BunkerWeb"}, allow_redirects=True, timeout=10)
|
||||
response.raise_for_status()
|
||||
|
||||
latest_version = basename(response.url)
|
||||
if current_version != latest_version:
|
||||
LOGGER.warning(f"* \n* \n* 🚨 A new version of BunkerWeb is available: {latest_version} (current: {current_version}) 🚨\n* \n* ")
|
||||
else:
|
||||
LOGGER.info(f"Latest version is already installed: {current_version}")
|
||||
except:
|
||||
status = 2
|
||||
LOGGER.error(f"Exception while running update-check.py :\n{format_exc()}")
|
||||
|
||||
sys_exit(status)
|
||||
|
|
@ -203,17 +203,17 @@
|
|||
"every": "once",
|
||||
"reload": false
|
||||
},
|
||||
{
|
||||
"name": "update-check",
|
||||
"file": "update-check.py",
|
||||
"every": "day",
|
||||
"reload": false
|
||||
},
|
||||
{
|
||||
"name": "anonymous-report",
|
||||
"file": "anonymous-report.py",
|
||||
"every": "day",
|
||||
"reload": false
|
||||
},
|
||||
{
|
||||
"name": "download-plugins",
|
||||
"file": "download-plugins.py",
|
||||
"every": "once",
|
||||
"reload": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
9
src/common/core/modsecurity/confs/modsec-crs/http3.conf
Normal file
9
src/common/core/modsecurity/confs/modsec-crs/http3.conf
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{% if USE_MODSECURITY == "yes" and MODSECURITY_CRS_VERSION == "3" and HTTP3 == "yes" +%}
|
||||
SecAction \
|
||||
"id:900230,\
|
||||
phase:1,\
|
||||
nolog,\
|
||||
pass,\
|
||||
t:none,\
|
||||
setvar:'tx.allowed_http_versions=HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/2.0 HTTP/3 HTTP/3.0'"
|
||||
{% endif %}
|
||||
|
|
@ -20,11 +20,11 @@ from jobs import Job # type: ignore
|
|||
|
||||
def check_line(line):
|
||||
with suppress(ValueError):
|
||||
if "/" in line:
|
||||
ip_network(line)
|
||||
if b"/" in line:
|
||||
ip_network(line.decode())
|
||||
return True, line
|
||||
else:
|
||||
ip_address(line)
|
||||
ip_address(line.decode())
|
||||
return True, line
|
||||
return False, b""
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from pathlib import Path
|
|||
from re import compile as re_compile
|
||||
from sys import argv, path as sys_path
|
||||
from threading import Lock
|
||||
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
|
||||
from typing import Any, Dict, List, Literal, Optional, Set, Tuple, Union
|
||||
from time import sleep
|
||||
from uuid import uuid4
|
||||
from zipfile import ZIP_DEFLATED, ZipFile
|
||||
|
|
@ -71,6 +71,7 @@ def set_sqlite_pragma(dbapi_connection, _):
|
|||
|
||||
class Database:
|
||||
DB_STRING_RX = re_compile(r"^(?P<database>(mariadb|mysql)(\+pymysql)?|sqlite(\+pysqlite)?|postgresql(\+psycopg)?):/+(?P<path>/[^\s]+)")
|
||||
READONLY_ERROR = ("readonly", "read-only", "command denied", "Access denied")
|
||||
|
||||
def __init__(
|
||||
self, logger: Logger, sqlalchemy_string: Optional[str] = None, *, ui: bool = False, pool: Optional[bool] = None, log: bool = True, **kwargs
|
||||
|
|
@ -78,7 +79,7 @@ class Database:
|
|||
"""Initialize the database"""
|
||||
self.logger = logger
|
||||
self.readonly = False
|
||||
self.last_fallback = None
|
||||
self.last_connection_retry = None
|
||||
|
||||
if pool:
|
||||
self.logger.warning("The pool parameter is deprecated, it will be removed in the next version")
|
||||
|
|
@ -133,6 +134,7 @@ class Database:
|
|||
"pool_recycle": 1800,
|
||||
"pool_size": 40,
|
||||
"max_overflow": 20,
|
||||
"pool_timeout": 5,
|
||||
} | kwargs
|
||||
|
||||
try:
|
||||
|
|
@ -183,19 +185,17 @@ class Database:
|
|||
self.sql_engine.dispose(close=True)
|
||||
self.sql_engine = create_engine(self.database_uri_readonly, **self._engine_kwargs)
|
||||
self.readonly = True
|
||||
self.last_fallback = datetime.now()
|
||||
fallback = True
|
||||
continue
|
||||
self.logger.error(f"Can't connect to database after {DATABASE_RETRY_TIMEOUT} seconds: {e}")
|
||||
_exit(1)
|
||||
|
||||
if "readonly" in str(e) or "read-only" in str(e) or "command denied" in str(e):
|
||||
if any(error in str(e) for error in self.READONLY_ERROR):
|
||||
if log:
|
||||
self.logger.warning("The database is read-only. Retrying in read-only mode in 5 seconds ...")
|
||||
self.sql_engine.dispose(close=True)
|
||||
self.sql_engine = create_engine(sqlalchemy_string, **self._engine_kwargs)
|
||||
self.readonly = True
|
||||
self.last_fallback = datetime.now()
|
||||
if "Unknown table" in str(e):
|
||||
not_connected = False
|
||||
continue
|
||||
|
|
@ -218,6 +218,12 @@ class Database:
|
|||
if self.sql_engine:
|
||||
self.sql_engine.dispose()
|
||||
|
||||
def test_read(self):
|
||||
"""Test the read access to the database"""
|
||||
self.logger.debug("Testing read access to the database ...")
|
||||
with self.__db_session() as session:
|
||||
session.execute(text("SELECT 1"))
|
||||
|
||||
def test_write(self):
|
||||
"""Test the write access to the database"""
|
||||
self.logger.debug("Testing write access to the database ...")
|
||||
|
|
@ -227,10 +233,12 @@ class Database:
|
|||
session.execute(text(f"DROP TABLE IF EXISTS test_{table_name}"))
|
||||
session.commit()
|
||||
|
||||
def retry_connection(self, *, readonly: bool = False, fallback: bool = False, **kwargs) -> None:
|
||||
def retry_connection(self, *, readonly: bool = False, fallback: bool = False, log: bool = True, **kwargs) -> None:
|
||||
"""Retry the connection to the database"""
|
||||
self.last_connection_retry = datetime.now()
|
||||
|
||||
self.logger.debug(f"Retrying the connection to the database {'in read-only mode' if readonly else ''}{' with fallback' if fallback else ''} ...")
|
||||
if log:
|
||||
self.logger.debug(f"Retrying the connection to the database{' in read-only mode' if readonly else ''}{' with fallback' if fallback else ''} ...")
|
||||
|
||||
assert self.sql_engine is not None
|
||||
|
||||
|
|
@ -245,9 +253,10 @@ class Database:
|
|||
conn.execute(text("SELECT 1"))
|
||||
return
|
||||
|
||||
table_name = uuid4().hex
|
||||
with self.sql_engine.connect() as conn:
|
||||
conn.execute(text("CREATE TABLE IF NOT EXISTS test (id INT)"))
|
||||
conn.execute(text("DROP TABLE test"))
|
||||
conn.execute(text(f"CREATE TABLE IF NOT EXISTS test_{table_name} (id INT)"))
|
||||
conn.execute(text(f"DROP TABLE IF EXISTS test_{table_name}"))
|
||||
|
||||
@contextmanager
|
||||
def __db_session(self) -> Any:
|
||||
|
|
@ -257,21 +266,6 @@ class Database:
|
|||
self.logger.error("The database engine is not initialized")
|
||||
_exit(1)
|
||||
|
||||
if self.database_uri and self.readonly and self.last_fallback and (datetime.now() - self.last_fallback).total_seconds() > 30:
|
||||
# ? If the database is forced to be read-only, we try to connect as a non read-only user every time until the database is writable
|
||||
try:
|
||||
self.retry_connection(pool_timeout=1)
|
||||
self.readonly = False
|
||||
self.logger.info("The database is no longer read-only, defaulting to read-write mode")
|
||||
except (OperationalError, DatabaseError):
|
||||
try:
|
||||
self.retry_connection(readonly=True, pool_timeout=1)
|
||||
except (OperationalError, DatabaseError):
|
||||
if self.database_uri_readonly:
|
||||
with suppress(OperationalError, DatabaseError):
|
||||
self.retry_connection(fallback=True, pool_timeout=1)
|
||||
self.readonly = True
|
||||
|
||||
with LOCK:
|
||||
session = None
|
||||
try:
|
||||
|
|
@ -283,24 +277,25 @@ class Database:
|
|||
if session:
|
||||
session.rollback()
|
||||
|
||||
if "readonly" in str(e) or "read-only" in str(e) or "command denied" in str(e):
|
||||
if any(error in str(e) for error in self.READONLY_ERROR):
|
||||
self.logger.warning("The database is read-only, retrying in read-only mode ...")
|
||||
try:
|
||||
self.retry_connection(readonly=True, pool_timeout=1)
|
||||
self.retry_connection(readonly=True, log=False)
|
||||
except (OperationalError, DatabaseError):
|
||||
if self.database_uri_readonly:
|
||||
self.logger.warning("Can't connect to the database in read-only mode, falling back to read-only one")
|
||||
with suppress(OperationalError, DatabaseError):
|
||||
self.retry_connection(fallback=True, pool_timeout=1)
|
||||
self.retry_connection(fallback=True, log=False)
|
||||
self.readonly = True
|
||||
self.last_fallback = datetime.now()
|
||||
elif isinstance(e, (ConnectionRefusedError, OperationalError)) and self.database_uri_readonly:
|
||||
self.logger.warning("Can't connect to the database, falling back to read-only one ...")
|
||||
with suppress(OperationalError, DatabaseError):
|
||||
self.retry_connection(fallback=True, pool_timeout=1)
|
||||
self.retry_connection(fallback=True, log=False)
|
||||
self.readonly = True
|
||||
self.last_fallback = datetime.now()
|
||||
raise
|
||||
raise
|
||||
finally:
|
||||
if session:
|
||||
session.remove()
|
||||
|
|
@ -349,8 +344,11 @@ class Database:
|
|||
"custom_configs_changed": False,
|
||||
"external_plugins_changed": False,
|
||||
"pro_plugins_changed": False,
|
||||
"config_changed": False,
|
||||
"instances_changed": False,
|
||||
"last_custom_configs_change": None,
|
||||
"last_external_plugins_change": None,
|
||||
"last_pro_plugins_change": None,
|
||||
"last_instances_change": None,
|
||||
"integration": "unknown",
|
||||
"version": "1.5.8",
|
||||
"database_version": "Unknown", # ? Extracted from the database
|
||||
|
|
@ -398,15 +396,15 @@ class Database:
|
|||
|
||||
return ""
|
||||
|
||||
def checked_changes(self, changes: Optional[List[str]] = None, value: Optional[bool] = False) -> str:
|
||||
def checked_changes(
|
||||
self,
|
||||
changes: Optional[List[str]] = None,
|
||||
plugins_changes: Optional[Union[Literal["all"], Set[str], List[str], Tuple[str]]] = None,
|
||||
value: Optional[bool] = False,
|
||||
) -> str:
|
||||
"""Set changed bit for config, custom configs, instances and plugins"""
|
||||
changes = changes or [
|
||||
"config",
|
||||
"custom_configs",
|
||||
"external_plugins",
|
||||
"pro_plugins",
|
||||
"instances",
|
||||
]
|
||||
changes = changes or ["config", "custom_configs", "external_plugins", "pro_plugins", "instances"]
|
||||
plugins_changes = plugins_changes or set()
|
||||
with self.__db_session() as session:
|
||||
if self.readonly:
|
||||
return "The database is read-only, the changes will not be saved"
|
||||
|
|
@ -417,18 +415,32 @@ class Database:
|
|||
if not metadata:
|
||||
return "The metadata are not set yet, try again"
|
||||
|
||||
current_time = datetime.now()
|
||||
|
||||
if "config" in changes:
|
||||
if not metadata.first_config_saved:
|
||||
metadata.first_config_saved = True
|
||||
metadata.config_changed = value
|
||||
if "custom_configs" in changes:
|
||||
metadata.custom_configs_changed = value
|
||||
metadata.last_custom_configs_change = current_time
|
||||
if "external_plugins" in changes:
|
||||
metadata.external_plugins_changed = value
|
||||
metadata.last_external_plugins_change = current_time
|
||||
if "pro_plugins" in changes:
|
||||
metadata.pro_plugins_changed = value
|
||||
metadata.last_pro_plugins_change = current_time
|
||||
if "instances" in changes:
|
||||
metadata.instances_changed = value
|
||||
metadata.last_instances_change = current_time
|
||||
|
||||
if plugins_changes:
|
||||
if plugins_changes == "all":
|
||||
session.query(Plugins).update({Plugins.config_changed: value, Plugins.last_config_change: current_time})
|
||||
else:
|
||||
session.query(Plugins).filter(Plugins.id.in_(plugins_changes)).update(
|
||||
{Plugins.config_changed: value, Plugins.last_config_change: current_time}
|
||||
)
|
||||
|
||||
session.commit()
|
||||
except BaseException as e:
|
||||
return str(e)
|
||||
|
|
@ -456,7 +468,7 @@ class Database:
|
|||
|
||||
if db_version != bunkerweb_version:
|
||||
self.logger.warning(f"Database version ({db_version}) is different from Bunkerweb version ({bunkerweb_version}), migrating ...")
|
||||
curren_time = datetime.now()
|
||||
current_time = datetime.now()
|
||||
error = True
|
||||
while error:
|
||||
try:
|
||||
|
|
@ -464,7 +476,7 @@ class Database:
|
|||
metadata.reflect(self.sql_engine)
|
||||
error = False
|
||||
except BaseException as e:
|
||||
if (datetime.now() - curren_time).total_seconds() > 10:
|
||||
if (datetime.now() - current_time).total_seconds() > 10:
|
||||
raise e
|
||||
sleep(1)
|
||||
|
||||
|
|
@ -971,7 +983,7 @@ class Database:
|
|||
|
||||
if db_version and db_version != bunkerweb_version:
|
||||
for table_name, data in old_data.items():
|
||||
if table_name == "bw_metadata" or not data:
|
||||
if not data:
|
||||
continue
|
||||
|
||||
self.logger.warning(f'Restoring data for table "{table_name}"')
|
||||
|
|
@ -990,6 +1002,15 @@ class Database:
|
|||
|
||||
with self.__db_session() as session:
|
||||
try:
|
||||
if table_name == "bw_metadata":
|
||||
existing_row = session.query(Metadata).filter_by(id=1).first()
|
||||
if not existing_row:
|
||||
session.add(Metadata(**row))
|
||||
session.commit()
|
||||
continue
|
||||
session.query(Metadata).filter_by(id=1).update(row)
|
||||
continue
|
||||
|
||||
# Check if the row already exists in the table
|
||||
existing_row = session.query(Base.metadata.tables[table_name]).filter_by(**row).first()
|
||||
if not existing_row:
|
||||
|
|
@ -1004,16 +1025,36 @@ class Database:
|
|||
|
||||
return True, ""
|
||||
|
||||
def save_config(self, config: Dict[str, Any], method: str, changed: Optional[bool] = True) -> str:
|
||||
def save_config(self, config: Dict[str, Any], method: str, changed: Optional[bool] = True) -> Union[str, Set[str]]:
|
||||
"""Save the config in the database"""
|
||||
to_put = []
|
||||
with self.__db_session() as session:
|
||||
if self.readonly:
|
||||
return "The database is read-only, the changes will not be saved"
|
||||
|
||||
# Delete all the old config
|
||||
session.query(Global_values).filter(Global_values.method == method).delete()
|
||||
session.query(Services_settings).filter(Services_settings.method == method).delete()
|
||||
changed_plugins = set()
|
||||
changed_services = False
|
||||
|
||||
for db_global_config in session.query(Global_values).filter_by(method=method).all():
|
||||
key = db_global_config.setting_id
|
||||
if db_global_config.suffix:
|
||||
key = f"{key}_{db_global_config.suffix}"
|
||||
|
||||
if key not in config and (db_global_config.suffix or f"{key}_0" not in config):
|
||||
session.delete(db_global_config)
|
||||
changed_plugins.add(session.query(Settings).with_entities(Settings.plugin_id).filter_by(id=db_global_config.setting_id).first().plugin_id)
|
||||
|
||||
if key == "SERVER_NAME":
|
||||
changed_services = True
|
||||
|
||||
for db_service_config in session.query(Services_settings).filter_by(method=method).all():
|
||||
key = f"{db_service_config.service_id}_{db_service_config.setting_id}"
|
||||
if db_service_config.suffix:
|
||||
key = f"{key}_{db_service_config.suffix}"
|
||||
|
||||
if key not in config and (db_service_config.suffix or f"{key}_0" not in config):
|
||||
session.delete(db_service_config)
|
||||
changed_plugins.add(session.query(Settings).with_entities(Settings.plugin_id).filter_by(id=db_service_config.setting_id).first().plugin_id)
|
||||
|
||||
if config:
|
||||
config.pop("DATABASE_URI", None)
|
||||
|
|
@ -1023,7 +1064,11 @@ class Database:
|
|||
services = config.get("SERVER_NAME", [])
|
||||
|
||||
if isinstance(services, str):
|
||||
services = services.split(" ")
|
||||
services = services.strip().split(" ")
|
||||
|
||||
for i, service in enumerate(services):
|
||||
if not service:
|
||||
services.pop(i)
|
||||
|
||||
if db_services:
|
||||
missing_ids = [service.id for service in db_services if service.method == method and service.id not in services]
|
||||
|
|
@ -1034,6 +1079,7 @@ class Database:
|
|||
session.query(Services_settings).filter(Services_settings.service_id.in_(missing_ids)).delete()
|
||||
session.query(Custom_configs).filter(Custom_configs.service_id.in_(missing_ids)).delete()
|
||||
session.query(Jobs_cache).filter(Jobs_cache.service_id.in_(missing_ids)).delete()
|
||||
changed_services = True
|
||||
|
||||
drafts = {service for service in services if config.pop(f"{service}_IS_DRAFT", "no") == "yes"}
|
||||
db_drafts = {service.id for service in db_services if service.is_draft}
|
||||
|
|
@ -1046,6 +1092,7 @@ class Database:
|
|||
if missing_drafts:
|
||||
# Remove drafts that are no longer in the list
|
||||
session.query(Services).filter(Services.id.in_(missing_drafts)).update({Services.is_draft: False})
|
||||
changed_services = True
|
||||
|
||||
for draft in drafts:
|
||||
if draft not in db_drafts:
|
||||
|
|
@ -1054,6 +1101,7 @@ class Database:
|
|||
db_ids[draft] = {"method": method, "is_draft": True}
|
||||
elif method == db_ids[draft]["method"]:
|
||||
session.query(Services).filter(Services.id == draft).update({Services.is_draft: True})
|
||||
changed_services = True
|
||||
|
||||
if config.get("MULTISITE", "no") == "yes":
|
||||
global_values = []
|
||||
|
|
@ -1064,7 +1112,7 @@ class Database:
|
|||
suffix = int(key.split("_")[-1])
|
||||
key = key[: -len(str(suffix)) - 1]
|
||||
|
||||
setting = session.query(Settings).with_entities(Settings.default).filter_by(id=key).first()
|
||||
setting = session.query(Settings).with_entities(Settings.default, Settings.plugin_id).filter_by(id=key).first()
|
||||
|
||||
if not setting and services:
|
||||
try:
|
||||
|
|
@ -1075,10 +1123,12 @@ class Database:
|
|||
if server_name not in db_ids:
|
||||
to_put.append(Services(id=server_name, method=method, is_draft=server_name in drafts))
|
||||
db_ids[server_name] = {"method": method, "is_draft": server_name in drafts}
|
||||
if server_name not in drafts:
|
||||
changed_services = True
|
||||
|
||||
key = key.replace(f"{server_name}_", "")
|
||||
original_key = original_key.replace(f"{server_name}_", "")
|
||||
setting = session.query(Settings).with_entities(Settings.default).filter_by(id=key).first()
|
||||
setting = session.query(Settings).with_entities(Settings.default, Settings.plugin_id).filter_by(id=key).first()
|
||||
|
||||
if not setting:
|
||||
continue
|
||||
|
|
@ -1086,11 +1136,7 @@ class Database:
|
|||
service_setting = (
|
||||
session.query(Services_settings)
|
||||
.with_entities(Services_settings.value, Services_settings.method)
|
||||
.filter_by(
|
||||
service_id=server_name,
|
||||
setting_id=key,
|
||||
suffix=suffix,
|
||||
)
|
||||
.filter_by(service_id=server_name, setting_id=key, suffix=suffix)
|
||||
.first()
|
||||
)
|
||||
|
||||
|
|
@ -1100,45 +1146,31 @@ class Database:
|
|||
):
|
||||
continue
|
||||
|
||||
to_put.append(
|
||||
Services_settings(
|
||||
service_id=server_name,
|
||||
setting_id=key,
|
||||
value=value,
|
||||
suffix=suffix,
|
||||
method=method,
|
||||
)
|
||||
)
|
||||
elif method in (service_setting.method, "autoconf") and service_setting.value != value:
|
||||
if key != "SERVER_NAME" and (
|
||||
(original_key not in config and value == setting.default) or (original_key in config and value == config[original_key])
|
||||
):
|
||||
session.query(Services_settings).filter(
|
||||
Services_settings.service_id == server_name,
|
||||
Services_settings.setting_id == key,
|
||||
Services_settings.suffix == suffix,
|
||||
).delete()
|
||||
continue
|
||||
|
||||
session.query(Services_settings).filter(
|
||||
changed_plugins.add(setting.plugin_id)
|
||||
to_put.append(Services_settings(service_id=server_name, setting_id=key, value=value, suffix=suffix, method=method))
|
||||
elif (
|
||||
method == service_setting.method or (service_setting.method not in ("scheduler", "autoconf") and method == "autoconf")
|
||||
) and service_setting.value != value:
|
||||
changed_plugins.add(setting.plugin_id)
|
||||
query = session.query(Services_settings).filter(
|
||||
Services_settings.service_id == server_name,
|
||||
Services_settings.setting_id == key,
|
||||
Services_settings.suffix == suffix,
|
||||
).update(
|
||||
{
|
||||
Services_settings.value: value,
|
||||
Services_settings.method: method,
|
||||
}
|
||||
)
|
||||
|
||||
if key != "SERVER_NAME" and (
|
||||
(original_key not in config and value == setting.default) or (original_key in config and value == config[original_key])
|
||||
):
|
||||
query.delete()
|
||||
continue
|
||||
|
||||
query.update({Services_settings.value: value, Services_settings.method: method})
|
||||
elif setting and original_key not in global_values:
|
||||
global_values.append(original_key)
|
||||
global_value = (
|
||||
session.query(Global_values)
|
||||
.with_entities(Global_values.value, Global_values.method)
|
||||
.filter_by(
|
||||
setting_id=key,
|
||||
suffix=suffix,
|
||||
)
|
||||
.filter_by(setting_id=key, suffix=suffix)
|
||||
.first()
|
||||
)
|
||||
|
||||
|
|
@ -1146,31 +1178,18 @@ class Database:
|
|||
if value == setting.default:
|
||||
continue
|
||||
|
||||
to_put.append(
|
||||
Global_values(
|
||||
setting_id=key,
|
||||
value=value,
|
||||
suffix=suffix,
|
||||
method=method,
|
||||
)
|
||||
)
|
||||
elif method in (global_value.method, "autoconf") and global_value.value != value:
|
||||
if value == setting.default:
|
||||
session.query(Global_values).filter(
|
||||
Global_values.setting_id == key,
|
||||
Global_values.suffix == suffix,
|
||||
).delete()
|
||||
continue
|
||||
changed_plugins.add(setting.plugin_id)
|
||||
to_put.append(Global_values(setting_id=key, value=value, suffix=suffix, method=method))
|
||||
elif (
|
||||
method == global_value.method or (global_value.method not in ("scheduler", "autoconf") and method == "autoconf")
|
||||
) and global_value.value != value:
|
||||
changed_plugins.add(setting.plugin_id)
|
||||
query = session.query(Global_values).filter(Global_values.setting_id == key, Global_values.suffix == suffix)
|
||||
|
||||
session.query(Global_values).filter(
|
||||
Global_values.setting_id == key,
|
||||
Global_values.suffix == suffix,
|
||||
).update(
|
||||
{
|
||||
Global_values.value: value,
|
||||
Global_values.method: method,
|
||||
}
|
||||
)
|
||||
if value == setting.default:
|
||||
query.delete()
|
||||
continue
|
||||
query.update({Global_values.value: value, Global_values.method: method})
|
||||
else:
|
||||
if (
|
||||
config.get("SERVER_NAME", "www.example.com")
|
||||
|
|
@ -1180,6 +1199,7 @@ class Database:
|
|||
.first()
|
||||
):
|
||||
to_put.append(Services(id=config.get("SERVER_NAME", "www.example.com").split(" ")[0], method=method))
|
||||
changed_services = True
|
||||
|
||||
for key, value in config.items():
|
||||
suffix = 0
|
||||
|
|
@ -1187,7 +1207,7 @@ class Database:
|
|||
suffix = int(key.split("_")[-1])
|
||||
key = key[: -len(str(suffix)) - 1]
|
||||
|
||||
setting = session.query(Settings).with_entities(Settings.default).filter_by(id=key).first()
|
||||
setting = session.query(Settings).with_entities(Settings.default, Settings.plugin_id).filter_by(id=key).first()
|
||||
|
||||
if not setting:
|
||||
continue
|
||||
|
|
@ -1203,26 +1223,21 @@ class Database:
|
|||
if value == setting.default:
|
||||
continue
|
||||
|
||||
to_put.append(
|
||||
Global_values(
|
||||
setting_id=key,
|
||||
value=value,
|
||||
suffix=suffix,
|
||||
method=method,
|
||||
)
|
||||
)
|
||||
elif global_value.method == method and value != global_value.value:
|
||||
if value == setting.default:
|
||||
session.query(Global_values).filter(
|
||||
Global_values.setting_id == key,
|
||||
Global_values.suffix == suffix,
|
||||
).delete()
|
||||
continue
|
||||
changed_plugins.add(setting.plugin_id)
|
||||
to_put.append(Global_values(setting_id=key, value=value, suffix=suffix, method=method))
|
||||
elif (
|
||||
method == global_value.method or (global_value.method not in ("scheduler", "autoconf") and method == "autoconf")
|
||||
) and value != global_value.value:
|
||||
changed_plugins.add(setting.plugin_id)
|
||||
query = session.query(Global_values).filter(Global_values.setting_id == key, Global_values.suffix == suffix)
|
||||
|
||||
session.query(Global_values).filter(
|
||||
Global_values.setting_id == key,
|
||||
Global_values.suffix == suffix,
|
||||
).update({Global_values.value: value})
|
||||
if value == setting.default:
|
||||
query.delete()
|
||||
continue
|
||||
query.update({Global_values.value: value, Global_values.method: method})
|
||||
|
||||
if changed_services:
|
||||
changed_plugins = set(plugin.id for plugin in session.query(Plugins).with_entities(Plugins.id).all())
|
||||
|
||||
if changed:
|
||||
with suppress(ProgrammingError, OperationalError):
|
||||
|
|
@ -1230,7 +1245,9 @@ class Database:
|
|||
if metadata is not None:
|
||||
if not metadata.first_config_saved:
|
||||
metadata.first_config_saved = True
|
||||
metadata.config_changed = True
|
||||
|
||||
if changed_plugins:
|
||||
session.query(Plugins).filter(Plugins.id.in_(changed_plugins)).update({Plugins.config_changed: True})
|
||||
|
||||
try:
|
||||
session.add_all(to_put)
|
||||
|
|
@ -1238,7 +1255,7 @@ class Database:
|
|||
except BaseException as e:
|
||||
return str(e)
|
||||
|
||||
return ""
|
||||
return changed_plugins
|
||||
|
||||
def save_custom_configs(
|
||||
self,
|
||||
|
|
@ -1313,17 +1330,18 @@ class Database:
|
|||
|
||||
if not custom_conf:
|
||||
to_put.append(Custom_configs(**custom_config))
|
||||
elif custom_config["checksum"] != custom_conf.checksum and method in (custom_conf.method, "autoconf"):
|
||||
elif custom_config["checksum"] != custom_conf.checksum and (
|
||||
method == custom_conf.method or (custom_conf.method not in ("scheduler", "autoconf") and method == "autoconf")
|
||||
):
|
||||
custom_conf.data = custom_config["data"]
|
||||
custom_conf.checksum = custom_config["checksum"]
|
||||
|
||||
if method == "autoconf":
|
||||
custom_conf.method = method
|
||||
custom_conf.method = method
|
||||
if changed:
|
||||
with suppress(ProgrammingError, OperationalError):
|
||||
metadata = session.query(Metadata).get(1)
|
||||
if metadata is not None:
|
||||
metadata.custom_configs_changed = True
|
||||
metadata.last_custom_configs_change = datetime.now()
|
||||
|
||||
try:
|
||||
session.add_all(to_put)
|
||||
|
|
@ -1333,7 +1351,7 @@ class Database:
|
|||
|
||||
return message
|
||||
|
||||
def get_config(self, methods: bool = False, with_drafts: bool = False) -> Dict[str, Any]:
|
||||
def get_config(self, global_only: bool = False, methods: bool = False, with_drafts: bool = False) -> Dict[str, Any]:
|
||||
"""Get the config from the database"""
|
||||
with self.__db_session() as session:
|
||||
config = {}
|
||||
|
|
@ -1373,7 +1391,7 @@ class Database:
|
|||
if not with_drafts:
|
||||
services = services.filter_by(is_draft=False)
|
||||
|
||||
if is_multisite:
|
||||
if not global_only and is_multisite:
|
||||
for service in services:
|
||||
config[f"{service.id}_IS_DRAFT"] = "yes" if service.is_draft else "no"
|
||||
if methods:
|
||||
|
|
@ -2050,8 +2068,10 @@ class Database:
|
|||
if metadata is not None:
|
||||
if _type == "external":
|
||||
metadata.external_plugins_changed = True
|
||||
metadata.last_external_plugins_change = datetime.now()
|
||||
elif _type == "pro":
|
||||
metadata.pro_plugins_changed = True
|
||||
metadata.last_pro_plugins_change = datetime.now()
|
||||
|
||||
try:
|
||||
session.add_all(to_put)
|
||||
|
|
@ -2267,6 +2287,7 @@ class Database:
|
|||
metadata = session.query(Metadata).get(1)
|
||||
if metadata is not None:
|
||||
metadata.instances_changed = True
|
||||
metadata.last_instances_change = datetime.now()
|
||||
|
||||
try:
|
||||
session.commit()
|
||||
|
|
@ -2299,6 +2320,7 @@ class Database:
|
|||
metadata = session.query(Metadata).get(1)
|
||||
if metadata is not None:
|
||||
metadata.instances_changed = True
|
||||
metadata.last_instances_change = datetime.now()
|
||||
|
||||
try:
|
||||
session.add_all(to_put)
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ class Plugins(Base):
|
|||
method = Column(METHODS_ENUM, default="manual", nullable=False)
|
||||
data = Column(LargeBinary(length=(2**32) - 1), nullable=True)
|
||||
checksum = Column(String(128), nullable=True)
|
||||
config_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_config_change = Column(DateTime, nullable=True)
|
||||
|
||||
settings = relationship("Settings", back_populates="plugin", cascade="all, delete-orphan")
|
||||
jobs = relationship("Jobs", back_populates="plugin", cascade="all, delete-orphan")
|
||||
|
|
@ -242,9 +244,12 @@ class Metadata(Base):
|
|||
autoconf_loaded = Column(Boolean, default=False, nullable=True)
|
||||
scheduler_first_start = Column(Boolean, nullable=True)
|
||||
custom_configs_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_custom_configs_change = Column(DateTime, nullable=True)
|
||||
external_plugins_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_external_plugins_change = Column(DateTime, nullable=True)
|
||||
pro_plugins_changed = Column(Boolean, default=False, nullable=True)
|
||||
config_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_pro_plugins_change = Column(DateTime, nullable=True)
|
||||
instances_changed = Column(Boolean, default=False, nullable=True)
|
||||
last_instances_change = Column(DateTime, nullable=True)
|
||||
integration = Column(INTEGRATIONS_ENUM, default="Unknown", nullable=False)
|
||||
version = Column(String(32), default="1.5.8", nullable=False)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
cryptography==42.0.7
|
||||
cryptography==42.0.8
|
||||
psycopg[c,pool]==3.1.19
|
||||
PyMySQL==1.1.1
|
||||
sqlalchemy==2.0.30
|
||||
|
|
|
|||
|
|
@ -58,39 +58,39 @@ cffi==1.16.0 \
|
|||
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
|
||||
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
|
||||
# via cryptography
|
||||
cryptography==42.0.7 \
|
||||
--hash=sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55 \
|
||||
--hash=sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785 \
|
||||
--hash=sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b \
|
||||
--hash=sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886 \
|
||||
--hash=sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82 \
|
||||
--hash=sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1 \
|
||||
--hash=sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda \
|
||||
--hash=sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f \
|
||||
--hash=sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68 \
|
||||
--hash=sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60 \
|
||||
--hash=sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7 \
|
||||
--hash=sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd \
|
||||
--hash=sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582 \
|
||||
--hash=sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc \
|
||||
--hash=sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858 \
|
||||
--hash=sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b \
|
||||
--hash=sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2 \
|
||||
--hash=sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678 \
|
||||
--hash=sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13 \
|
||||
--hash=sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4 \
|
||||
--hash=sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8 \
|
||||
--hash=sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604 \
|
||||
--hash=sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477 \
|
||||
--hash=sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e \
|
||||
--hash=sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a \
|
||||
--hash=sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9 \
|
||||
--hash=sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14 \
|
||||
--hash=sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda \
|
||||
--hash=sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da \
|
||||
--hash=sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562 \
|
||||
--hash=sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2 \
|
||||
--hash=sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9
|
||||
cryptography==42.0.8 \
|
||||
--hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \
|
||||
--hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \
|
||||
--hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \
|
||||
--hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \
|
||||
--hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \
|
||||
--hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \
|
||||
--hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \
|
||||
--hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \
|
||||
--hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \
|
||||
--hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \
|
||||
--hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \
|
||||
--hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \
|
||||
--hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \
|
||||
--hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \
|
||||
--hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \
|
||||
--hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \
|
||||
--hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \
|
||||
--hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \
|
||||
--hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \
|
||||
--hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \
|
||||
--hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \
|
||||
--hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \
|
||||
--hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \
|
||||
--hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \
|
||||
--hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \
|
||||
--hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \
|
||||
--hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \
|
||||
--hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \
|
||||
--hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \
|
||||
--hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \
|
||||
--hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \
|
||||
--hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e
|
||||
# via -r requirements.armv7.in
|
||||
greenlet==3.0.3 \
|
||||
--hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \
|
||||
|
|
@ -222,9 +222,9 @@ sqlalchemy==2.0.30 \
|
|||
--hash=sha256:f7703c2010355dd28f53deb644a05fc30f796bd8598b43f0ba678878780b6e4c \
|
||||
--hash=sha256:fa561138a64f949f3e889eb9ab8c58e1504ab351d6cf55259dc4c248eaa19da6
|
||||
# via -r requirements.armv7.in
|
||||
typing-extensions==4.12.0 \
|
||||
--hash=sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8 \
|
||||
--hash=sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594
|
||||
typing-extensions==4.12.2 \
|
||||
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
|
||||
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
|
||||
# via
|
||||
# psycopg
|
||||
# psycopg-pool
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
cryptography==42.0.7
|
||||
cryptography==42.0.8
|
||||
psycopg[binary,pool]==3.1.19
|
||||
PyMySQL==1.1.1
|
||||
sqlalchemy==2.0.30
|
||||
|
|
|
|||
|
|
@ -58,39 +58,39 @@ cffi==1.16.0 \
|
|||
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
|
||||
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
|
||||
# via cryptography
|
||||
cryptography==42.0.7 \
|
||||
--hash=sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55 \
|
||||
--hash=sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785 \
|
||||
--hash=sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b \
|
||||
--hash=sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886 \
|
||||
--hash=sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82 \
|
||||
--hash=sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1 \
|
||||
--hash=sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda \
|
||||
--hash=sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f \
|
||||
--hash=sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68 \
|
||||
--hash=sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60 \
|
||||
--hash=sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7 \
|
||||
--hash=sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd \
|
||||
--hash=sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582 \
|
||||
--hash=sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc \
|
||||
--hash=sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858 \
|
||||
--hash=sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b \
|
||||
--hash=sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2 \
|
||||
--hash=sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678 \
|
||||
--hash=sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13 \
|
||||
--hash=sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4 \
|
||||
--hash=sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8 \
|
||||
--hash=sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604 \
|
||||
--hash=sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477 \
|
||||
--hash=sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e \
|
||||
--hash=sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a \
|
||||
--hash=sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9 \
|
||||
--hash=sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14 \
|
||||
--hash=sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda \
|
||||
--hash=sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da \
|
||||
--hash=sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562 \
|
||||
--hash=sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2 \
|
||||
--hash=sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9
|
||||
cryptography==42.0.8 \
|
||||
--hash=sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad \
|
||||
--hash=sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583 \
|
||||
--hash=sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b \
|
||||
--hash=sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c \
|
||||
--hash=sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1 \
|
||||
--hash=sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648 \
|
||||
--hash=sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949 \
|
||||
--hash=sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba \
|
||||
--hash=sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c \
|
||||
--hash=sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9 \
|
||||
--hash=sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d \
|
||||
--hash=sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c \
|
||||
--hash=sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e \
|
||||
--hash=sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2 \
|
||||
--hash=sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d \
|
||||
--hash=sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7 \
|
||||
--hash=sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70 \
|
||||
--hash=sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2 \
|
||||
--hash=sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7 \
|
||||
--hash=sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14 \
|
||||
--hash=sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe \
|
||||
--hash=sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e \
|
||||
--hash=sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71 \
|
||||
--hash=sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961 \
|
||||
--hash=sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7 \
|
||||
--hash=sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c \
|
||||
--hash=sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28 \
|
||||
--hash=sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842 \
|
||||
--hash=sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902 \
|
||||
--hash=sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801 \
|
||||
--hash=sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a \
|
||||
--hash=sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e
|
||||
# via -r requirements.in
|
||||
greenlet==3.0.3 \
|
||||
--hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \
|
||||
|
|
@ -284,9 +284,9 @@ sqlalchemy==2.0.30 \
|
|||
--hash=sha256:f7703c2010355dd28f53deb644a05fc30f796bd8598b43f0ba678878780b6e4c \
|
||||
--hash=sha256:fa561138a64f949f3e889eb9ab8c58e1504ab351d6cf55259dc4c248eaa19da6
|
||||
# via -r requirements.in
|
||||
typing-extensions==4.12.0 \
|
||||
--hash=sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8 \
|
||||
--hash=sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594
|
||||
typing-extensions==4.12.2 \
|
||||
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
|
||||
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
|
||||
# via
|
||||
# psycopg
|
||||
# psycopg-pool
|
||||
|
|
|
|||
|
|
@ -86,6 +86,9 @@ class Configurator:
|
|||
return {}
|
||||
servers = {}
|
||||
for server_name in self.__variables["SERVER_NAME"].strip().split(" "):
|
||||
if not server_name:
|
||||
continue
|
||||
|
||||
if not re_search(self.__settings["SERVER_NAME"]["regex"], server_name):
|
||||
self.__logger.warning(f"Ignoring server name {server_name} because regex is not valid")
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ if __name__ == "__main__":
|
|||
parser.add_argument("--output", default=join(sep, "etc", "nginx"), type=str, help="where to write the rendered files")
|
||||
parser.add_argument("--target", default=join(sep, "etc", "nginx"), type=str, help="where nginx will search for configurations files")
|
||||
parser.add_argument("--variables", type=str, help="path to the file containing environment variables")
|
||||
parser.add_argument("--no-linux-reload", action="store_true", help="disable linux reload")
|
||||
args = parser.parse_args()
|
||||
|
||||
settings_path = Path(args.settings)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
jinja2==3.1.4
|
||||
python-dotenv==1.0.1
|
||||
redis==5.0.4
|
||||
requests==2.32.2
|
||||
redis==5.0.5
|
||||
requests==2.32.3
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ async-timeout==4.0.3 \
|
|||
--hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \
|
||||
--hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028
|
||||
# via redis
|
||||
certifi==2024.2.2 \
|
||||
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
||||
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
||||
certifi==2024.6.2 \
|
||||
--hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \
|
||||
--hash=sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56
|
||||
# via requests
|
||||
charset-normalizer==3.3.2 \
|
||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||
|
|
@ -178,13 +178,13 @@ python-dotenv==1.0.1 \
|
|||
--hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \
|
||||
--hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a
|
||||
# via -r requirements.in
|
||||
redis==5.0.4 \
|
||||
--hash=sha256:7adc2835c7a9b5033b7ad8f8918d09b7344188228809c98df07af226d39dec91 \
|
||||
--hash=sha256:ec31f2ed9675cc54c21ba854cfe0462e6faf1d83c8ce5944709db8a4700b9c61
|
||||
redis==5.0.5 \
|
||||
--hash=sha256:30b47d4ebb6b7a0b9b40c1275a19b87bb6f46b3bed82a89012cf56dea4024ada \
|
||||
--hash=sha256:3417688621acf6ee368dec4a04dd95881be24efd34c79f00d31f62bb528800ae
|
||||
# via -r requirements.in
|
||||
requests==2.32.2 \
|
||||
--hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \
|
||||
--hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
|
||||
requests==2.32.3 \
|
||||
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||
# via -r requirements.in
|
||||
urllib3==2.2.1 \
|
||||
--hash=sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d \
|
||||
|
|
|
|||
|
|
@ -90,6 +90,8 @@ if __name__ == "__main__":
|
|||
LOGGER.error(f"Missing RX rights on directory : {path}")
|
||||
sys_exit(1)
|
||||
|
||||
tmp_config = {}
|
||||
|
||||
if args.variables:
|
||||
variables_path = Path(args.variables)
|
||||
LOGGER.info(f"Variables : {variables_path}")
|
||||
|
|
@ -191,11 +193,13 @@ if __name__ == "__main__":
|
|||
sys_exit(0)
|
||||
|
||||
changes = []
|
||||
changed_plugins = set()
|
||||
err = db.save_config(settings, args.method, changed=False)
|
||||
|
||||
if err:
|
||||
if isinstance(err, str):
|
||||
LOGGER.warning(f"Couldn't save config to database : {err}, config may not work as expected")
|
||||
else:
|
||||
changed_plugins = err
|
||||
changes.append("config")
|
||||
LOGGER.info("Config successfully saved to database")
|
||||
|
||||
|
|
@ -220,7 +224,7 @@ if __name__ == "__main__":
|
|||
|
||||
if not args.no_check_changes:
|
||||
# update changes in db
|
||||
ret = db.checked_changes(changes, value=True)
|
||||
ret = db.checked_changes(changes, plugins_changes=changed_plugins, value=True)
|
||||
if ret:
|
||||
LOGGER.error(f"An error occurred when setting the changes to checked in the database : {ret}")
|
||||
except SystemExit as e:
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from glob import glob
|
||||
from json import JSONDecodeError, loads
|
||||
from os import sep
|
||||
from os.path import join
|
||||
from pathlib import Path
|
||||
from re import match
|
||||
from traceback import format_exc
|
||||
from typing import Any, Dict, Literal, Union
|
||||
|
||||
from logger import setup_logger
|
||||
|
||||
|
||||
class ConfigCaller:
|
||||
def __init__(self):
|
||||
self.__logger = setup_logger("Config", "INFO")
|
||||
self._settings = loads(Path(sep, "usr", "share", "bunkerweb", "settings.json").read_text(encoding="utf-8"))
|
||||
for plugin in glob(join(sep, "usr", "share", "bunkerweb", "core", "*", "plugin.json")) + glob(
|
||||
join(sep, "etc", "bunkerweb", "plugins", "*", "plugin.json")
|
||||
):
|
||||
try:
|
||||
self._settings.update(loads(Path(plugin).read_text(encoding="utf-8"))["settings"])
|
||||
except KeyError:
|
||||
self.__logger.error(
|
||||
f'Error while loading plugin metadata file at {plugin} : missing "settings" key',
|
||||
)
|
||||
except JSONDecodeError:
|
||||
self.__logger.error(
|
||||
f"Exception while loading plugin metadata file at {plugin} :\n{format_exc()}",
|
||||
)
|
||||
|
||||
def _is_setting(self, setting) -> bool:
|
||||
return setting in self._settings
|
||||
|
||||
def _is_setting_context(self, setting: str, context: Union[Literal["global"], Literal["multisite"]]) -> bool:
|
||||
if self._is_setting(setting):
|
||||
return self._settings[setting]["context"] == context
|
||||
elif match(r"^.+_\d+$", setting):
|
||||
multiple_setting = "_".join(setting.split("_")[:-1])
|
||||
return (
|
||||
self._is_setting(multiple_setting) and self._settings[multiple_setting]["context"] == context and "multiple" in self._settings[multiple_setting]
|
||||
)
|
||||
return False
|
||||
|
||||
def _full_env(self, env_instances: Dict[str, Any], env_services: Dict[str, Any]) -> Dict[str, Any]:
|
||||
full_env = {}
|
||||
# Fill with default values
|
||||
for k, v in self._settings.items():
|
||||
full_env[k] = v["default"]
|
||||
# Replace with instances values
|
||||
for k, v in env_instances.items():
|
||||
full_env[k] = v
|
||||
if not self._is_setting_context(k, "global") and env_instances.get("MULTISITE", "no") == "yes" and env_instances.get("SERVER_NAME", "") != "":
|
||||
for server_name in env_instances["SERVER_NAME"].split(" "):
|
||||
full_env[f"{server_name}_{k}"] = v
|
||||
# Replace with services values
|
||||
full_env = full_env | env_services
|
||||
return full_env
|
||||
|
|
@ -25,8 +25,8 @@ setLoggerClass(BWLogger)
|
|||
|
||||
default_level = _nameToLevel.get(getenv("CUSTOM_LOG_LEVEL", getenv("LOG_LEVEL", "INFO")).upper(), INFO)
|
||||
basicConfig(
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
datefmt="[%Y-%m-%d %H:%M:%S]",
|
||||
format="%(asctime)s [%(name)s] [%(process)d] [%(levelname)s] - %(message)s",
|
||||
datefmt="[%Y-%m-%d %H:%M:%S %z]",
|
||||
level=default_level,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,13 +25,13 @@
|
|||
"name": "ModSecurity-nginx v1.0.3",
|
||||
"url": "https://github.com/SpiderLabs/ModSecurity-nginx.git",
|
||||
"commit": "d59e4ad121df702751940fd66bcc0b3ecb51a079",
|
||||
"post_install": "patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_log.c src/deps/misc/modsecurity-nginx.patch && patch --forward src/deps/src/modsecurity-nginx/config src/deps/misc/config.patch && patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_common.h src/deps/misc/ngx_http_modsecurity_common.h.patch && patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_module.c src/deps/misc/ngx_http_modsecurity_module.c.patch && patch --forward src/deps/src/modsecurity-nginx/config src/deps/misc/modsecurity-nginx-config.patch"
|
||||
"post_install": "patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_log.c src/deps/misc/modsecurity-nginx.patch && patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_common.h src/deps/misc/ngx_http_modsecurity_common.h.patch && patch --forward src/deps/src/modsecurity-nginx/src/ngx_http_modsecurity_module.c src/deps/misc/ngx_http_modsecurity_module.c.patch && patch --forward src/deps/src/modsecurity-nginx/config src/deps/misc/modsecurity-nginx-config.patch"
|
||||
},
|
||||
{
|
||||
"id": "nginx",
|
||||
"name": "Nginx v1.26.0",
|
||||
"name": "Nginx v1.26.1",
|
||||
"url": "https://github.com/nginx/nginx.git",
|
||||
"commit": "361f6bf4b1cd5057d8f6365d1c0a94f3d72824e4"
|
||||
"commit": "02725ce722bc7b34fa307d611eac3956ef744efa"
|
||||
},
|
||||
{
|
||||
"id": "ngx_brotli",
|
||||
|
|
@ -151,9 +151,9 @@
|
|||
},
|
||||
{
|
||||
"id": "lua-resty-openssl",
|
||||
"name": "lua-resty-openssl v1.3.1",
|
||||
"name": "lua-resty-openssl v1.4.0",
|
||||
"url": "https://github.com/fffonion/lua-resty-openssl.git",
|
||||
"commit": "643956d990b3ef4d9b52d0b77ba4d69d7e912dcc",
|
||||
"commit": "e56da6c5f285ff0e40fce703b870e83ee8eac321",
|
||||
"post_install": "rm -r src/deps/src/lua-resty-openssl/t"
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -169,8 +169,7 @@ do_and_check_cmd make PREFIX=/usr/share/bunkerweb/deps LUA_LIB_DIR=/usr/share/bu
|
|||
# Installing lua-resty-openssl
|
||||
echo "ℹ️ Installing lua-resty-openssl"
|
||||
export CHANGE_DIR="/tmp/bunkerweb/deps/src/lua-resty-openssl"
|
||||
do_and_check_cmd make LUA_LIB_DIR=/usr/share/bunkerweb/deps/lib/lua install
|
||||
do_and_check_cmd bash -c "mv lib/resty/openssl.lua /usr/share/bunkerweb/deps/lib/lua/resty/"
|
||||
do_and_check_cmd make PREFIX=/usr/share/bunkerweb/deps LUA_LIB_DIR=/usr/share/bunkerweb/deps/lib/lua install
|
||||
|
||||
# Installing lua-ffi-zlib
|
||||
echo "ℹ️ Installing lua-ffi-zlib"
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
@@ -110,7 +110,7 @@
|
||||
ngx_module_type=HTTP_FILTER
|
||||
ngx_module_name="$ngx_addon_name"
|
||||
ngx_module_srcs="$ngx_addon_dir/src/ngx_http_modsecurity_module.c \
|
||||
- $ngx_addon_dir/src/ngx_http_modsecurity_pre_access.c \
|
||||
+ $ngx_addon_dir/src/ngx_http_modsecurity_access.c \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_header_filter.c \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_body_filter.c \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_log.c \
|
||||
@@ -141,7 +141,7 @@
|
||||
NGX_ADDON_SRCS="\
|
||||
$NGX_ADDON_SRCS \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_module.c \
|
||||
- $ngx_addon_dir/src/ngx_http_modsecurity_pre_access.c \
|
||||
+ $ngx_addon_dir/src/ngx_http_modsecurity_access.c \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_header_filter.c \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_body_filter.c \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_log.c \
|
||||
|
|
@ -1,8 +1,19 @@
|
|||
@@ -126,6 +126,7 @@
|
||||
ngx_http_v2_filter_module \
|
||||
ngx_http_range_header_filter_module \
|
||||
@@ -14,3 +14,3 @@
|
||||
ngx_feature_libs="-lmodsecurity"
|
||||
-ngx_feature_test='printf("hello");'
|
||||
+ngx_feature_test='msc_init();'
|
||||
ngx_modsecurity_opt_I=
|
||||
@@ -112,3 +112,3 @@
|
||||
ngx_module_srcs="$ngx_addon_dir/src/ngx_http_modsecurity_module.c \
|
||||
- $ngx_addon_dir/src/ngx_http_modsecurity_pre_access.c \
|
||||
+ $ngx_addon_dir/src/ngx_http_modsecurity_access.c \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_header_filter.c \
|
||||
@@ -128,2 +128,3 @@
|
||||
ngx_http_gzip_filter_module \
|
||||
+ ngx_http_brotli_filter_module \
|
||||
$ngx_module_name \
|
||||
$modsecurity_dependency";
|
||||
|
||||
@@ -143,3 +144,3 @@
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_module.c \
|
||||
- $ngx_addon_dir/src/ngx_http_modsecurity_pre_access.c \
|
||||
+ $ngx_addon_dir/src/ngx_http_modsecurity_access.c \
|
||||
$ngx_addon_dir/src/ngx_http_modsecurity_header_filter.c \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
pip==24.0
|
||||
pip-compile-multi==2.6.3
|
||||
pip-compile-multi==2.6.4
|
||||
pip-tools==7.4.1
|
||||
pip-upgrader==1.4.15
|
||||
setuptools==70.0.0
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ build==1.2.1 \
|
|||
--hash=sha256:526263f4870c26f26c433545579475377b2b7588b6f1eac76a001e873ae3e19d \
|
||||
--hash=sha256:75e10f767a433d9a86e50d83f418e83efc18ede923ee5ff7df93b6cb0306c5d4
|
||||
# via pip-tools
|
||||
certifi==2024.2.2 \
|
||||
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
|
||||
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
|
||||
certifi==2024.6.2 \
|
||||
--hash=sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516 \
|
||||
--hash=sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56
|
||||
# via requests
|
||||
charset-normalizer==3.3.2 \
|
||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||
|
|
@ -137,9 +137,9 @@ pip==24.0 \
|
|||
# via
|
||||
# build
|
||||
# pip-upgrader
|
||||
pip-compile-multi==2.6.3 \
|
||||
--hash=sha256:50f7db9f5c57a2d11035805b6d86620c4d640c560f22e3c8b509e133456d8a53 \
|
||||
--hash=sha256:f0b950a2175d0b86fd5a186d2f786bc8f7c013acd2e856a2bc948d194e0e4c92
|
||||
pip-compile-multi==2.6.4 \
|
||||
--hash=sha256:1cf1f1eaa68b7993303edf83e0dc40b8b9bb4dced334b0c18332f4aeae318e3b \
|
||||
--hash=sha256:487741913c0eba7aeee6e0cd79fe123df3a22f3489e565c9851eb259dd3c3d52
|
||||
# via -r requirements-deps.in
|
||||
pip-tools==7.4.1 \
|
||||
--hash=sha256:4c690e5fbae2f21e87843e89c26191f0d9454f362d8acdbd695716493ec8b3a9 \
|
||||
|
|
@ -157,9 +157,9 @@ pyproject-hooks==1.1.0 \
|
|||
# via
|
||||
# build
|
||||
# pip-tools
|
||||
requests==2.32.2 \
|
||||
--hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \
|
||||
--hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
|
||||
requests==2.32.3 \
|
||||
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||
# via
|
||||
# -r requirements-deps.in
|
||||
# pip-tools
|
||||
|
|
@ -192,9 +192,9 @@ wheel==0.43.0 \
|
|||
# via
|
||||
# -r requirements-deps.in
|
||||
# pip-tools
|
||||
zipp==3.18.2 \
|
||||
--hash=sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059 \
|
||||
--hash=sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e
|
||||
zipp==3.19.2 \
|
||||
--hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \
|
||||
--hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c
|
||||
# via
|
||||
# -r requirements-deps.in
|
||||
# pip-tools
|
||||
|
|
|
|||
|
|
@ -54,9 +54,9 @@ wheel==0.43.0 \
|
|||
# via
|
||||
# -r requirements.in
|
||||
# pip-tools
|
||||
zipp==3.18.2 \
|
||||
--hash=sha256:6278d9ddbcfb1f1089a88fde84481528b07b0e10474e09dcfe53dad4069fa059 \
|
||||
--hash=sha256:dce197b859eb796242b0622af1b8beb0a722d52aa2f57133ead08edd5bf5374e
|
||||
zipp==3.19.2 \
|
||||
--hash=sha256:bf1dcf6450f873a13e952a29504887c89e6de7506209e5b1bcc3460135d4de19 \
|
||||
--hash=sha256:f091755f667055f2d02b32c53771a7a6c8b47e1fdbc4b72a8b9072b3eef8015c
|
||||
# via
|
||||
# -r requirements.in
|
||||
# pip-tools
|
||||
|
|
|
|||
|
|
@ -30,14 +30,14 @@ jobs:
|
|||
# latest and one version older for valgrind and perf test
|
||||
- nginx: "1.19.9"
|
||||
openssl: "3.1.5"
|
||||
openssl_fips: "3.0.8"
|
||||
openssl_fips: "3.0.9"
|
||||
extras: "valgrind"
|
||||
lua_nginx_module: "v0.10.20"
|
||||
lua_resty_core: "v0.1.22"
|
||||
nginx_cc_opts: "-Wno-error"
|
||||
- nginx: "1.21.4"
|
||||
openssl: "3.1.5"
|
||||
openssl_fips: "3.0.8"
|
||||
openssl_fips: "3.0.9"
|
||||
extras: "valgrind"
|
||||
lua_nginx_module: "v0.10.25"
|
||||
lua_resty_core: "v0.1.27"
|
||||
|
|
@ -49,25 +49,33 @@ jobs:
|
|||
lua_resty_core: "v0.1.28"
|
||||
- nginx: "1.25.3"
|
||||
openssl: "3.0.13"
|
||||
openssl_fips: "3.0.8"
|
||||
openssl_fips: "3.0.9"
|
||||
extras: "valgrind perf lua-kong-nginx-module"
|
||||
lua_nginx_module: "v0.10.26"
|
||||
lua_resty_core: "v0.1.28"
|
||||
nginx_cc_opts: "-Wno-error"
|
||||
- nginx: "1.25.3"
|
||||
openssl: "3.1.5"
|
||||
openssl_fips: "3.0.8"
|
||||
openssl_fips: "3.0.9"
|
||||
extras: "valgrind perf lua-kong-nginx-module"
|
||||
lua_nginx_module: "v0.10.26"
|
||||
lua_resty_core: "v0.1.28"
|
||||
nginx_cc_opts: "-Wno-error"
|
||||
- nginx: "1.25.3"
|
||||
openssl: "3.2.1"
|
||||
openssl_fips: "3.0.8"
|
||||
openssl_fips: "3.0.9"
|
||||
extras: "valgrind perf lua-kong-nginx-module"
|
||||
lua_nginx_module: "v0.10.26"
|
||||
lua_resty_core: "v0.1.28"
|
||||
nginx_cc_opts: "-Wno-error"
|
||||
- nginx: "1.25.3"
|
||||
openssl: "3.3.0"
|
||||
openssl_fips: "3.0.9"
|
||||
extras: "valgrind perf lua-kong-nginx-module"
|
||||
lua_nginx_module: "v0.10.26"
|
||||
lua_resty_core: "v0.1.28"
|
||||
nginx_cc_opts: "-Wno-error"
|
||||
|
||||
|
||||
env:
|
||||
JOBS: 3
|
||||
|
|
|
|||
17
src/deps/src/lua-resty-openssl/CHANGELOG.md
vendored
17
src/deps/src/lua-resty-openssl/CHANGELOG.md
vendored
|
|
@ -2,12 +2,22 @@
|
|||
## [Unreleased]
|
||||
|
||||
|
||||
<a name="1.4.0"></a>
|
||||
## [1.4.0] - 2024-05-27
|
||||
### bug fixes
|
||||
- **ec:** add missing cdef for EC_POINT_free [2093e88](https://github.com/fffonion/lua-resty-openssl/commit/2093e8814ccfbe830ba594a71f05870cac208e9c)
|
||||
|
||||
### features
|
||||
- **pkey:** allow pkey.new to compose from parameters [91a30f6](https://github.com/fffonion/lua-resty-openssl/commit/91a30f6988e3fc696363ce1445b49a3f6ee8f35e)
|
||||
- **pkey:** add pkey:verify_raw [0016308](https://github.com/fffonion/lua-resty-openssl/commit/0016308c9e3a2ccfdfe674ede64e462060f7b13b)
|
||||
|
||||
|
||||
<a name="1.3.1"></a>
|
||||
## [1.3.1] - 2024-04-22
|
||||
### bug fixes
|
||||
- **aux/jwk:** remove ecx.d if exporting as public key [9d34ff8](https://github.com/fffonion/lua-resty-openssl/commit/9d34ff8fd79debbcf155f74af0b161083b6a8385)
|
||||
- **aux/nginx:** fix the typo of get_socket_ssl in the stream module [0aa315e](https://github.com/fffonion/lua-resty-openssl/commit/0aa315efe3d98d38d8d77dedf687958b62d8b184)
|
||||
- **aux/nginx:** remove extra sanity test that prevent usage of lua-kong-nginx-module [7bd2d0a](https://github.com/fffonion/lua-resty-openssl/commit/7bd2d0aabe82219071fe9fd1b30e49ff88bd5472)
|
||||
- **aux/nginx:** fix the typo of get_socket_ssl in the stream module [ad18b3c](https://github.com/fffonion/lua-resty-openssl/commit/ad18b3c18c7ec3db175aabfbf6928141c3b53b17)
|
||||
- **aux/nginx:** remove extra sanity test that prevent usage of lua-kong-nginx-module [2323526](https://github.com/fffonion/lua-resty-openssl/commit/2323526766b131bde94052449c41a331e93288bd)
|
||||
|
||||
|
||||
<a name="1.3.0"></a>
|
||||
|
|
@ -591,7 +601,8 @@
|
|||
- **x509:** export pubkey [ede4f81](https://github.com/fffonion/lua-resty-openssl/commit/ede4f817cb0fe092ad6f9ab5d6ecdcde864a9fd8)
|
||||
|
||||
|
||||
[Unreleased]: https://github.com/fffonion/lua-resty-openssl/compare/1.3.1...HEAD
|
||||
[Unreleased]: https://github.com/fffonion/lua-resty-openssl/compare/1.4.0...HEAD
|
||||
[1.4.0]: https://github.com/fffonion/lua-resty-openssl/compare/1.3.1...1.4.0
|
||||
[1.3.1]: https://github.com/fffonion/lua-resty-openssl/compare/1.3.0...1.3.1
|
||||
[1.3.0]: https://github.com/fffonion/lua-resty-openssl/compare/1.2.1...1.3.0
|
||||
[1.2.1]: https://github.com/fffonion/lua-resty-openssl/compare/1.2.0...1.2.1
|
||||
|
|
|
|||
48
src/deps/src/lua-resty-openssl/README.md
vendored
48
src/deps/src/lua-resty-openssl/README.md
vendored
|
|
@ -66,6 +66,7 @@ Table of Contents
|
|||
+ [pkey:encrypt](#pkeyencrypt)
|
||||
+ [pkey:decrypt](#pkeydecrypt)
|
||||
+ [pkey:sign_raw](#pkeysign_raw)
|
||||
+ [pkey:verify_raw](#pkeyverify_raw)
|
||||
+ [pkey:verify_recover](#pkeyverify_recover)
|
||||
+ [pkey:derive](#pkeyderive)
|
||||
+ [pkey:tostring](#pkeytostring)
|
||||
|
|
@ -871,13 +872,14 @@ for EC keys. See [pkey:sign](#pkeysign) and [pkey.verify](#pkeyverify) for detai
|
|||
- When running outside of OpenResty, needs to install a JSON library (`cjson` or `dkjson`)
|
||||
and `basexx`.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
#### Key generation
|
||||
|
||||
**syntax**: *pk, err = pkey.new(config?)*
|
||||
|
||||
Generate a new public key or private key.
|
||||
|
||||
|
||||
To generate RSA key, `config` table can have `bits` and `exp` field to control key generation.
|
||||
When `config` is emitted, this function generates a 2048 bit RSA key with `exponent` of 65537,
|
||||
which is equivalent to:
|
||||
|
|
@ -936,6 +938,27 @@ pkey.new({
|
|||
|
||||
```
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
#### Key composition
|
||||
|
||||
**syntax**: *pk, err = pkey.new(config?)*
|
||||
|
||||
Compose a public or private key using existing parameters. To see
|
||||
list of parameters for each key, refer to [pkey:set_parameters](#pkeyset_parameters).
|
||||
|
||||
Only `type` and `params` should exist in `config` table, all other keys will be ignored.
|
||||
|
||||
```lua
|
||||
local private_bn = require "resty.openssl.bn".new("7F48282CCA4C1A65D589C06DBE9C42AE50FBFFDF3A18CBB48498E1DE47F11BE1A3486CD8FA950D68F111970F922279D8", 16)
|
||||
local p_384, err = assert(require("resty.openssl.pkey").new({
|
||||
type = "EC",
|
||||
params = {
|
||||
private = private_bn,
|
||||
group = "secp384r1",
|
||||
}
|
||||
}))
|
||||
```
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
|
|
@ -1195,6 +1218,8 @@ pk:sign(message, nil, nil, {
|
|||
-- in pkeyutl CLI the above is equivalent to: `openssl pkeyutl -sign -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256
|
||||
```
|
||||
|
||||
To sign a message without doing message digest, please check [pkey:sign_raw](#pkeysign_raw).
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
### pkey:verify
|
||||
|
|
@ -1262,6 +1287,8 @@ ngx.say(ngx.encode_base64(signature))
|
|||
|
||||
```
|
||||
|
||||
To verify a message without doing message digest, please check [pkey:verify_raw](#pkeyverify_raw) and [pkey:verify_recover](#pkeyverify_recover).
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
### pkey:encrypt
|
||||
|
|
@ -1325,6 +1352,25 @@ for an example.
|
|||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
### pkey:verify_raw
|
||||
|
||||
**syntax**: *ok, err = pk:verify_raw(signature, data, md_alg, padding?, opts?)*
|
||||
|
||||
Verify the cipher text `signature` with the message `data` with pkey instance, which must loaded a public key. Set the message digest to `md_alg` but doesn't do message digest
|
||||
automatically, in other words, this function assumes `data` has already been hashed with `md_alg`.
|
||||
|
||||
When `md_alg` is undefined, for RSA and EC keys, this function does SHA256 by default. For Ed25519 or Ed448 keys, no default value is set.
|
||||
|
||||
The optinal fourth argument `padding` has same meaning as in [pkey:sign](#pkeysign).
|
||||
If omitted, `padding` is default to `pkey.PADDINGS.RSA_PKCS1_PADDING`.
|
||||
|
||||
The fifth optional argument `opts` has same meaning as in [pkey:sign](#pkeysign).
|
||||
|
||||
See [examples/raw-sign-and-recover.lua](https://github.com/fffonion/lua-resty-openssl/blob/master/examples/raw-sign-and-recover.lua)
|
||||
for an example.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
### pkey:verify_recover
|
||||
|
||||
**syntax**: *txt, err = pk:verify_recover(signature, padding?, opts?)*
|
||||
|
|
|
|||
|
|
@ -7,11 +7,29 @@ local original = "original text"
|
|||
|
||||
-- same as nodejs: crypto.privateEncrypt
|
||||
-- php: openssl_private_encrypt
|
||||
local digested = assert(priv:sign_raw(original))
|
||||
local signed = assert(priv:sign_raw(original))
|
||||
|
||||
print("Digested message: " .. ngx.encode_base64(digested))
|
||||
print("Signed message: " .. ngx.encode_base64(signed))
|
||||
|
||||
-- same as nodejs: crypto.publicDecrypt
|
||||
-- php: openssl_public_decrypt
|
||||
local recovered = assert(pub:verify_recover(digested))
|
||||
local recovered = assert(pub:verify_recover(signed))
|
||||
print("Recovered message: " .. recovered)
|
||||
|
||||
|
||||
local priv = assert(pkey.new({
|
||||
type = "EC",
|
||||
}))
|
||||
local pub = assert(pkey.new(priv:to_PEM("public")))
|
||||
local md_alg = "sha512"
|
||||
|
||||
local hashed = require "resty.openssl.digest".new(md_alg):final(original)
|
||||
|
||||
local signed = assert(priv:sign_raw(hashed))
|
||||
|
||||
print("Signed message: " .. ngx.encode_base64(signed))
|
||||
|
||||
-- same as nodejs: crypto.publicDecrypt
|
||||
-- php: openssl_public_decrypt
|
||||
local verified = assert(pub:verify_raw(signed, hashed, md_alg))
|
||||
print("Verification result: ", verified)
|
||||
|
|
@ -24,7 +24,7 @@ try_require_modules()
|
|||
|
||||
|
||||
local _M = {
|
||||
_VERSION = '1.3.1',
|
||||
_VERSION = '1.4.0',
|
||||
}
|
||||
|
||||
function _M.load_modules()
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ function _M.load_jwk(txt)
|
|||
if key ~= nil then
|
||||
return key
|
||||
end
|
||||
key_free = function() end
|
||||
else
|
||||
return nil, "not yet supported jwk type \"" .. (tbl["kty"] or "nil") .. "\""
|
||||
end
|
||||
|
|
|
|||
|
|
@ -125,7 +125,8 @@ else
|
|||
} ngx_connection_s;
|
||||
]]
|
||||
else
|
||||
error("resty.openssl.auxiliary.nginx doesn't support Nginx version " .. ngx_version, 2)
|
||||
error("resty.openssl.auxiliary.nginx development mode doesn't support Nginx version " .. ngx_version ..
|
||||
", please compile nginx with lua-resty-openssl-aux-module or lua-kong-nginx-module.", 2)
|
||||
end
|
||||
|
||||
ffi.cdef [[
|
||||
|
|
@ -167,7 +168,8 @@ else
|
|||
local NO_C_MODULE_WARNING_MSG_SHOWN = false
|
||||
local NO_C_MODULE_WARNING_MSG = "note resty.openssl.auxiliary.nginx is using plain FFI " ..
|
||||
"and it's only intended to be used in development, " ..
|
||||
"consider using lua-resty-openssl.aux-module in production."
|
||||
"consider using lua-resty-openssl-aux-module or " ..
|
||||
"lua-kong-nginx-module in production."
|
||||
|
||||
local function get_ngx_ssl_from_req()
|
||||
if not NO_C_MODULE_WARNING_MSG_SHOWN then
|
||||
|
|
|
|||
|
|
@ -158,6 +158,8 @@ function _M.set_parameters(ec_key_st, opts)
|
|||
end
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
return _M
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ ffi.cdef [[
|
|||
BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
|
||||
EC_POINT *EC_POINT_bn2point(const EC_GROUP *group, const BIGNUM *bn,
|
||||
EC_POINT *p, BN_CTX *ctx);
|
||||
void EC_POINT_free(EC_POINT *point);
|
||||
|
||||
point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ ffi.cdef [[
|
|||
int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *sig, size_t *siglen,
|
||||
const unsigned char *tbs, size_t tbslen);
|
||||
int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_verify(EVP_PKEY_CTX *ctx,
|
||||
const unsigned char *sig, size_t siglen,
|
||||
const unsigned char *tbs, size_t tbslen);
|
||||
int EVP_PKEY_verify_recover_init(EVP_PKEY_CTX *ctx);
|
||||
int EVP_PKEY_verify_recover(EVP_PKEY_CTX *ctx,
|
||||
unsigned char *rout, size_t *routlen,
|
||||
|
|
|
|||
|
|
@ -402,6 +402,67 @@ local function generate_key(config)
|
|||
return ctx_ptr[0]
|
||||
end
|
||||
|
||||
local function compose_key(config)
|
||||
local typ = config.type or 'RSA'
|
||||
local key_type
|
||||
|
||||
if typ == "RSA" then
|
||||
key_type = evp_macro.EVP_PKEY_RSA
|
||||
elseif typ == "EC" then
|
||||
key_type = evp_macro.EVP_PKEY_EC
|
||||
elseif evp_macro.ecx_curves[typ] then
|
||||
key_type = evp_macro.ecx_curves[typ]
|
||||
else
|
||||
return nil, "unsupported type " .. typ
|
||||
end
|
||||
if key_type == 0 then
|
||||
return nil, "the linked OpenSSL library doesn't support " .. typ .. " key"
|
||||
end
|
||||
|
||||
local key, err, key_free, _
|
||||
|
||||
if key_type == evp_macro.EVP_PKEY_EC then
|
||||
key = C.EC_KEY_new()
|
||||
if key == nil then
|
||||
return nil, "EC_KEY_new failed"
|
||||
end
|
||||
key_free = C.EC_KEY_free
|
||||
_, err = ec_lib.set_parameters(key, config.params)
|
||||
elseif key_type == evp_macro.EVP_PKEY_RSA then
|
||||
key = C.RSA_new()
|
||||
if key == nil then
|
||||
return nil, "RSA_new failed"
|
||||
end
|
||||
key_free = C.RSA_free
|
||||
_, err = rsa_lib.set_parameters(key, config.params)
|
||||
elseif key_type == evp_macro.EVP_PKEY_ED25519 or
|
||||
key_type == evp_macro.EVP_PKEY_X25519 or
|
||||
key_type == evp_macro.EVP_PKEY_ED448 or
|
||||
key_type == evp_macro.EVP_PKEY_X448 then
|
||||
key_free = function() end
|
||||
key, err = ecx_lib.set_parameters(key_type, nil, config.params)
|
||||
end
|
||||
|
||||
if err then
|
||||
return nil, "failed to construct " .. typ.. " key from parameters: " .. err
|
||||
end
|
||||
|
||||
local ctx = C.EVP_PKEY_new()
|
||||
if ctx == nil then
|
||||
key_free(key)
|
||||
return nil, "EVP_PKEY_new() failed"
|
||||
end
|
||||
|
||||
local code = C.EVP_PKEY_assign(ctx, key_type, key)
|
||||
if code ~= 1 then
|
||||
key_free(key)
|
||||
C.EVP_PKEY_free(ctx)
|
||||
return nil, "EVP_PKEY_assign() failed"
|
||||
end
|
||||
|
||||
return ctx
|
||||
end
|
||||
|
||||
local load_key_try_funcs = {} do
|
||||
-- TODO: pkcs1 load functions are not required in openssl 3.0
|
||||
local _load_key_try_funcs = {
|
||||
|
|
@ -506,9 +567,13 @@ function _M.new(s, opts)
|
|||
local ctx, err
|
||||
s = s or {}
|
||||
if type(s) == 'table' then
|
||||
ctx, err = generate_key(s)
|
||||
if s.params then
|
||||
ctx, err = compose_key(s)
|
||||
else
|
||||
ctx, err = generate_key(s)
|
||||
end
|
||||
if err then
|
||||
err = "pkey.new:generate_key: " .. err
|
||||
err = "pkey.new:new_key: " .. err
|
||||
end
|
||||
elseif type(s) == 'string' then
|
||||
ctx, err = load_pem_der(s, opts or empty_table, load_key_try_funcs)
|
||||
|
|
@ -656,8 +721,9 @@ end
|
|||
|
||||
local ASYMMETRIC_OP_ENCRYPT = 0x1
|
||||
local ASYMMETRIC_OP_DECRYPT = 0x2
|
||||
local ASYMMETRIC_OP_SIGN_RAW = 0x4
|
||||
local ASYMMETRIC_OP_VERIFY_RECOVER = 0x8
|
||||
local ASYMMETRIC_OP_SIGN_RAW = 0x3
|
||||
local ASYMMETRIC_OP_VERIFY_RAW = 0x4
|
||||
local ASYMMETRIC_OP_VERIFY_RECOVER = 0x5
|
||||
|
||||
local function asymmetric_routine(self, s, op, padding, opts)
|
||||
if type(s) ~= "string" then
|
||||
|
|
@ -701,6 +767,10 @@ local function asymmetric_routine(self, s, op, padding, opts)
|
|||
fint = C.EVP_PKEY_sign_init
|
||||
f = C.EVP_PKEY_sign
|
||||
op_name = "sign"
|
||||
elseif op == ASYMMETRIC_OP_VERIFY_RAW then
|
||||
fint = C.EVP_PKEY_verify_init
|
||||
f = C.EVP_PKEY_verify
|
||||
op_name = "verify"
|
||||
elseif op == ASYMMETRIC_OP_VERIFY_RECOVER then
|
||||
fint = C.EVP_PKEY_verify_recover_init
|
||||
f = C.EVP_PKEY_verify_recover
|
||||
|
|
@ -725,13 +795,25 @@ local function asymmetric_routine(self, s, op, padding, opts)
|
|||
return nil, "pkey:asymmetric_routine: " .. err
|
||||
end
|
||||
|
||||
local length = ptr_of_size_t(self.buf_size)
|
||||
|
||||
if f(pkey_ctx, self.buf, length, s, #s) <= 0 then
|
||||
return nil, format_error("pkey:asymmetric_routine EVP_PKEY_" .. op_name)
|
||||
local buf, buf_len
|
||||
if opts and opts.buf_in then
|
||||
buf = opts.buf_in
|
||||
buf_len = #buf
|
||||
else
|
||||
buf = self.buf
|
||||
buf_len = ptr_of_size_t(self.buf_size)
|
||||
end
|
||||
|
||||
return ffi_str(self.buf, length[0]), nil
|
||||
code = f(pkey_ctx, buf, buf_len, s, #s)
|
||||
if code <= 0 then
|
||||
return nil, format_error("pkey:asymmetric_routine EVP_PKEY_" .. op_name, code)
|
||||
end
|
||||
|
||||
if not opts or not opts.buf_in then
|
||||
return ffi_str(self.buf, buf_len[0]), nil
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
_M.PADDINGS = rsa_macro.paddings
|
||||
|
|
@ -753,6 +835,16 @@ function _M:sign_raw(s, padding, opts)
|
|||
return asymmetric_routine(self, s, ASYMMETRIC_OP_SIGN_RAW, padding, opts)
|
||||
end
|
||||
|
||||
function _M:verify_raw(signature, hashed_message, md_alg, padding, opts)
|
||||
opts = opts or {}
|
||||
opts.buf_in = signature
|
||||
if md_alg then
|
||||
table.insert(opts, "digest:" .. md_alg)
|
||||
end
|
||||
|
||||
return asymmetric_routine(self, hashed_message, ASYMMETRIC_OP_VERIFY_RAW, padding, opts)
|
||||
end
|
||||
|
||||
function _M:verify_recover(s, padding, opts)
|
||||
return asymmetric_routine(self, s, ASYMMETRIC_OP_VERIFY_RECOVER, padding, opts)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package = "lua-resty-openssl"
|
||||
version = "1.3.1-1"
|
||||
version = "1.4.0-1"
|
||||
source = {
|
||||
url = "git+https://github.com/fffonion/lua-resty-openssl.git",
|
||||
tag = "1.3.1"
|
||||
tag = "1.4.0"
|
||||
}
|
||||
description = {
|
||||
detailed = "FFI-based OpenSSL binding for LuaJIT.",
|
||||
|
|
@ -1 +1 @@
|
|||
jinja2==3.1.3
|
||||
jinja2==3.1.4
|
||||
|
|
|
|||
4
src/deps/src/modsecurity-nginx/config
vendored
4
src/deps/src/modsecurity-nginx/config
vendored
|
|
@ -12,7 +12,7 @@ ngx_feature_name=
|
|||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <modsecurity/modsecurity.h>"
|
||||
ngx_feature_libs="-lmodsecurity"
|
||||
ngx_feature_test='printf("hello");'
|
||||
ngx_feature_test='msc_init();'
|
||||
ngx_modsecurity_opt_I=
|
||||
ngx_modsecurity_opt_L=
|
||||
|
||||
|
|
@ -190,4 +190,4 @@ if [ "$ngx_module_link" != DYNAMIC ] ; then
|
|||
exit 1
|
||||
fi
|
||||
HTTP_FILTER_MODULES="${modules}"
|
||||
fi
|
||||
fi
|
||||
1
src/deps/src/nginx/.hgtags
vendored
1
src/deps/src/nginx/.hgtags
vendored
|
|
@ -478,3 +478,4 @@ f8134640e8615448205785cf00b0bc810489b495 release-1.25.1
|
|||
294a3d07234f8f65d7b0e0b0e2c5b05c12c5da0a release-1.25.3
|
||||
173a0a7dbce569adbb70257c6ec4f0f6bc585009 release-1.25.4
|
||||
8618e4d900cc71082fbe7dc72af087937d64faf5 release-1.25.5
|
||||
a58202a8c41bf0bd97eef1b946e13105a105520d release-1.26.0
|
||||
|
|
|
|||
2
src/deps/src/nginx/auto/lib/libatomic/conf
vendored
2
src/deps/src/nginx/auto/lib/libatomic/conf
vendored
|
|
@ -19,7 +19,7 @@ else
|
|||
#include <atomic_ops.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-latomic_ops"
|
||||
ngx_feature_test="long n = 0;
|
||||
ngx_feature_test="AO_t n = 0;
|
||||
if (!AO_compare_and_swap(&n, 0, 1))
|
||||
return 1;
|
||||
if (AO_fetch_and_add(&n, 1) != 1)
|
||||
|
|
|
|||
56
src/deps/src/nginx/docs/xml/nginx/changes.xml
vendored
56
src/deps/src/nginx/docs/xml/nginx/changes.xml
vendored
|
|
@ -5,6 +5,62 @@
|
|||
<change_log title="nginx">
|
||||
|
||||
|
||||
<changes ver="1.26.1" date="2024-05-29">
|
||||
|
||||
<change type="security">
|
||||
<para lang="ru">
|
||||
при использовании HTTP/3 обработка специально созданной QUIC-сессии могла
|
||||
приводить к падению рабочего процесса, отправке клиенту содержимого памяти
|
||||
рабочего процесса на системах с MTU больше 4096 байт, а также потенциально
|
||||
могла иметь другие последствия
|
||||
(CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161).<br/>
|
||||
Спасибо Nils Bars из CISPA.
|
||||
</para>
|
||||
<para lang="en">
|
||||
when using HTTP/3, processing of a specially crafted QUIC session might
|
||||
cause a worker process crash, worker process memory disclosure on systems
|
||||
with MTU larger than 4096 bytes, or might have potential other impact
|
||||
(CVE-2024-32760, CVE-2024-31079, CVE-2024-35200, CVE-2024-34161).<br/>
|
||||
Thanks to Nils Bars of CISPA.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="bugfix">
|
||||
<para lang="ru">
|
||||
уменьшено потребление памяти для долгоживущих запросов,
|
||||
если используются директивы gzip, gunzip, ssi, sub_filter или grpc_pass.
|
||||
</para>
|
||||
<para lang="en">
|
||||
reduced memory consumption for long-lived requests
|
||||
if "gzip", "gunzip", "ssi", "sub_filter", or "grpc_pass" directives are used.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="bugfix">
|
||||
<para lang="ru">
|
||||
nginx не собирался gcc 14,
|
||||
если использовался параметр --with-atomic.<br/>
|
||||
Спасибо Edgar Bonet.
|
||||
</para>
|
||||
<para lang="en">
|
||||
nginx could not be built by gcc 14
|
||||
if the --with-atomic option was used.<br/>
|
||||
Thanks to Edgar Bonet.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
<change type="bugfix">
|
||||
<para lang="ru">
|
||||
в HTTP/3.
|
||||
</para>
|
||||
<para lang="en">
|
||||
in HTTP/3.
|
||||
</para>
|
||||
</change>
|
||||
|
||||
</changes>
|
||||
|
||||
|
||||
<changes ver="1.26.0" date="2024-04-23">
|
||||
|
||||
<change>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue