├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── alert-docs.yml │ ├── ci.yml │ ├── crowdin-build-translations.yml │ ├── crowdin-download-translations.yml │ ├── event-docs.yml │ ├── handle-release.yml │ ├── update-add-on-release.yml │ ├── update-daily-release.yml │ └── update-main-release.yml ├── .gitignore ├── README.md ├── ZapVersions-2.10.xml ├── ZapVersions-2.11.xml ├── ZapVersions-2.12.xml ├── ZapVersions-2.13.xml ├── ZapVersions-2.14.xml ├── ZapVersions-2.15.xml ├── ZapVersions-2.16.xml ├── ZapVersions-2.4.xml ├── ZapVersions-2.5.xml ├── ZapVersions-2.6.xml ├── ZapVersions-2.7.xml ├── ZapVersions-2.8.xml ├── ZapVersions-2.9.xml ├── ZapVersions-dev.xml ├── ZapVersions.xml ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts ├── settings.gradle.kts └── src │ └── main │ ├── java │ └── org │ │ └── zaproxy │ │ └── gradle │ │ ├── AbstractGenerateWebsiteReleaseData.java │ │ ├── AbstractUpdateZapVersionsEntries.java │ │ ├── AddOnReleaseData.java │ │ ├── AddOnZapVersionsUpdater.java │ │ ├── CreateNewsMainRelease.java │ │ ├── CreatePullRequest.java │ │ ├── CreatePullRequestImpl.java │ │ ├── CustomXmlConfiguration.java │ │ ├── DownloadReleasedAddOns.java │ │ ├── GenerateReleaseStateLastCommit.java │ │ ├── GenerateWebsiteAddonsData.java │ │ ├── GenerateWebsiteMainReleaseData.java │ │ ├── GenerateWebsitePages.java │ │ ├── GenerateWebsiteSbomPages.java │ │ ├── GenerateWebsiteWeeklyReleaseData.java │ │ ├── HandleMainRelease.java │ │ ├── HandleWeeklyRelease.java │ │ ├── ReleaseData.java │ │ ├── ReleaseState.java │ │ ├── SendRepositoryDispatch.java │ │ ├── TaskException.java │ │ ├── TaskUtils.java │ │ ├── UpdateAddOnZapVersionsEntries.java │ │ ├── UpdateAndCreatePullRequestAddOnRelease.java │ │ ├── UpdateDailyZapVersionsEntries.java │ │ ├── UpdateFlathubData.java │ │ ├── UpdateGettingStartedWebsitePage.java │ │ ├── UpdateMainZapVersionsEntries.java │ │ ├── UpdateZapVersionWebsiteData.java │ │ ├── UpdateZapVersionsEntries.java │ │ ├── crowdin │ │ ├── BuildEntry.java │ │ ├── BuildTask.java │ │ └── DeployCrowdinTranslations.java │ │ └── website │ │ ├── HelpSetFactory.java │ │ ├── PageFrontMatter.java │ │ ├── SourceImage.java │ │ ├── SourcePage.java │ │ ├── TocTree.java │ │ ├── Utils.java │ │ ├── WebsitePageGenerationException.java │ │ ├── WebsitePageGenerator.java │ │ └── WebsiteSbomPageGenerator.java │ └── kotlin │ └── org │ └── zaproxy │ └── gradle │ ├── GitHubRepo.kt │ ├── GitHubUser.kt │ └── ZapTask.kt ├── docs ├── headers │ ├── README.MD │ ├── license.java │ └── license.script └── issue-templates │ └── README.MD ├── files ├── launch │ ├── 2.6.html │ ├── 2.7.html │ ├── 2.8.html │ ├── README.md │ └── dev.html └── news │ ├── 2_10.xml │ ├── 2_11.xml │ ├── 2_12.xml │ ├── 2_13.xml │ ├── 2_14.xml │ ├── 2_15.xml │ ├── 2_16.xml │ ├── 2_8.xml │ ├── 2_9.xml │ └── dev.xml ├── gradle ├── ci.gradle.kts ├── crowdin.yml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── scripts ├── generate_alert_pages.js ├── generate_events_page.js ├── raise_issue.py └── report_addons_to_release.sh ├── settings.gradle.kts └── src ├── main ├── addons-help-website.txt ├── crowdin-tasks.yml ├── java │ └── org │ │ └── zaproxy │ │ └── admin │ │ ├── AddOnsTask.java │ │ ├── CheckLatestReleaseNotes.java │ │ ├── CountDownloads.java │ │ ├── GenerateReleaseNotes.java │ │ ├── HelpGenerator.java │ │ ├── PendingAddOnReleases.java │ │ └── Utils.java └── resources │ └── org │ └── zaproxy │ └── admin │ └── resources │ └── help │ ├── contents │ ├── addon.html │ └── images │ │ └── cake.png │ ├── helpset.hs │ ├── index.xml │ ├── map.jhm │ └── toc.xml └── test └── java └── org └── zaproxy └── admin ├── ValidateZapVersionsXmlTest.java └── VerifyCoreZapVersionsEntries.java /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.gradle text 4 | *.java text 5 | *.jhm text 6 | *.properties text 7 | *.psf text 8 | *.py text 9 | *.md text 10 | *.html text 11 | *.hs text 12 | *.script text 13 | *.xml text 14 | 15 | *.bat eol=crlf 16 | *.sh text 17 | gradlew text 18 | 19 | *.jar binary 20 | *.png binary -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | groups: 8 | gha: 9 | applies-to: version-updates 10 | patterns: 11 | - "*" 12 | -------------------------------------------------------------------------------- /.github/workflows/alert-docs.yml: -------------------------------------------------------------------------------- 1 | name: Generate alert docs for website 2 | on: 3 | workflow_dispatch: 4 | schedule: # The start of every Friday 5 | - cron: '0 0 * * 5' 6 | 7 | jobs: 8 | update-alerts: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | with: 14 | path: zap-admin 15 | - name: Checkout zaproxy-website 16 | uses: actions/checkout@v4 17 | with: 18 | repository: zaproxy/zaproxy-website 19 | persist-credentials: false 20 | path: zaproxy-website 21 | fetch-depth: 0 22 | - name: Update alert docs 23 | env: 24 | GITHUB_TOKEN: ${{ secrets.ZAPBOT_TOKEN }} 25 | run: | 26 | # Setup git details 27 | export GITHUB_USER=zapbot 28 | git config --global user.email "12745184+zapbot@users.noreply.github.com" 29 | git config --global user.name $GITHUB_USER 30 | # Run the ZAP script 31 | docker run -v $(pwd):/zap/wrk/:rw --user root -t ghcr.io/zaproxy/zaproxy:nightly ./zap.sh -addoninstallall -silent -script /zap/wrk/zap-admin/scripts/generate_alert_pages.js -cmd 32 | cd zaproxy-website 33 | git checkout -b update-alerts 34 | # Update the index to be sure git is aware of changes 35 | git update-index -q --refresh 36 | git add site/content/docs/alerts/ site/data/alerttags.yml 37 | ## If there are changes: comment, commit, PR 38 | if ! git diff-index --quiet HEAD --; then 39 | git remote set-url origin https://$GITHUB_USER:$GITHUB_TOKEN@github.com/$GITHUB_USER/zaproxy-website.git 40 | git commit -m "Update alert pages" --signoff 41 | git push --set-upstream origin update-alerts --force 42 | gh pr create -R zaproxy/zaproxy-website -f 43 | fi -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | java: [17, 21, 22] 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: actions/setup-java@v4 19 | with: 20 | distribution: 'temurin' 21 | java-version: ${{ matrix.java }} 22 | - uses: gradle/actions/setup-gradle@8379f6a1328ee0e06e2bb424dadb7b159856a326 # v4.4.0 23 | - run: ./gradlew assemble 24 | - run: ./gradlew check 25 | -------------------------------------------------------------------------------- /.github/workflows/crowdin-build-translations.yml: -------------------------------------------------------------------------------- 1 | name: Crowdin Build Translations 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 5 * * 1,4' 7 | 8 | jobs: 9 | build: 10 | name: Build Translations 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Setup Java 15 | uses: actions/setup-java@v4 16 | with: 17 | distribution: 'temurin' 18 | java-version: 17 19 | - name: Build Translations 20 | env: 21 | CROWDIN_AUTH_TOKEN: ${{ secrets.ZAPBOT_CROWDIN_TOKEN }} 22 | run: ./gradlew crowdinBuildProjectTranslation 23 | -------------------------------------------------------------------------------- /.github/workflows/crowdin-download-translations.yml: -------------------------------------------------------------------------------- 1 | name: Crowdin Download Translations 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '30 6 * * 1,4' 7 | 8 | jobs: 9 | download: 10 | name: Download Translations 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Setup Java 15 | uses: actions/setup-java@v4 16 | with: 17 | distribution: 'temurin' 18 | java-version: 17 19 | - name: Download Translations 20 | env: 21 | CROWDIN_AUTH_TOKEN: ${{ secrets.ZAPBOT_CROWDIN_TOKEN }} 22 | ZAPBOT_TOKEN: ${{ secrets.ZAPBOT_TOKEN }} 23 | run: ./gradlew crowdinDownloadProjectTranslation && ./gradlew deployCrowdinTranslations 24 | -------------------------------------------------------------------------------- /.github/workflows/event-docs.yml: -------------------------------------------------------------------------------- 1 | name: Generate events page for website 2 | on: 3 | workflow_dispatch: 4 | 5 | jobs: 6 | update-events: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | with: 12 | path: zap-admin 13 | - name: Checkout zaproxy-website 14 | uses: actions/checkout@v4 15 | with: 16 | repository: zaproxy/zaproxy-website 17 | persist-credentials: false 18 | path: zaproxy-website 19 | fetch-depth: 0 20 | - name: Update events page 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.ZAPBOT_TOKEN }} 23 | run: | 24 | # Setup git details 25 | export GITHUB_USER=zapbot 26 | git config --global user.email "12745184+zapbot@users.noreply.github.com" 27 | git config --global user.name $GITHUB_USER 28 | # Run the ZAP script 29 | docker run -v $(pwd):/zap/wrk/:rw --user root -t ghcr.io/zaproxy/zaproxy:nightly ./zap.sh -addoninstallall -silent -script /zap/wrk/zap-admin/scripts/generate_events_page.js -cmd 30 | cd zaproxy-website 31 | git checkout -b update-events 32 | # Update the index to be sure git is aware of changes 33 | git update-index -q --refresh 34 | # Generate a PR 35 | git remote set-url origin https://$GITHUB_USER:$GITHUB_TOKEN@github.com/$GITHUB_USER/zaproxy-website.git 36 | git add site/data/events.yaml 37 | git commit -m "Update events page" --signoff 38 | git push --set-upstream origin update-events --force 39 | gh pr create -R zaproxy/zaproxy-website -f 40 | -------------------------------------------------------------------------------- /.github/workflows/handle-release.yml: -------------------------------------------------------------------------------- 1 | name: Handle Release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | paths: 9 | - ZapVersions*.xml 10 | 11 | jobs: 12 | handle-release: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v4 17 | with: 18 | path: zap-admin 19 | fetch-depth: 10 20 | - name: Checkout zaproxy-website 21 | uses: actions/checkout@v4 22 | with: 23 | repository: zaproxy/zaproxy-website 24 | persist-credentials: false 25 | path: zaproxy-website 26 | fetch-depth: 0 27 | - name: Checkout org.zaproxy.ZAP 28 | uses: actions/checkout@v4 29 | with: 30 | repository: flathub/org.zaproxy.ZAP 31 | persist-credentials: false 32 | path: org.zaproxy.ZAP 33 | fetch-depth: 0 34 | - name: Setup Java 35 | uses: actions/setup-java@v4 36 | with: 37 | distribution: 'temurin' 38 | java-version: 17 39 | - name: Handle Release 40 | run: cd zap-admin && ./gradlew handleRelease 41 | env: 42 | ZAPBOT_TOKEN: ${{ secrets.ZAPBOT_TOKEN }} 43 | -------------------------------------------------------------------------------- /.github/workflows/update-add-on-release.yml: -------------------------------------------------------------------------------- 1 | name: Update Add-on Release 2 | 3 | on: 4 | repository_dispatch: 5 | types: 'add-on-release' 6 | 7 | jobs: 8 | add-on-release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 15 | persist-credentials: false 16 | - name: Setup Java 17 | uses: actions/setup-java@v4 18 | with: 19 | distribution: 'temurin' 20 | java-version: 17 21 | - name: Process Client Payload 22 | run: | 23 | echo "ADD_ON_DATA<<'EOF'" >> $GITHUB_ENV 24 | echo '${{ toJSON(github.event.client_payload) }}' >> $GITHUB_ENV 25 | echo "'EOF'" >> $GITHUB_ENV 26 | - name: Update Add-on Release and Create Pull Request 27 | run: ./gradlew updateAndCreatePullRequestAddOnRelease --envVar=ADD_ON_DATA 28 | env: 29 | ZAPBOT_TOKEN: ${{ secrets.ZAPBOT_TOKEN }} 30 | -------------------------------------------------------------------------------- /.github/workflows/update-daily-release.yml: -------------------------------------------------------------------------------- 1 | name: Update Daily Release 2 | 3 | on: 4 | repository_dispatch: 5 | types: 'daily-release' 6 | 7 | jobs: 8 | daily-release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 15 | persist-credentials: false 16 | - name: Setup Java 17 | uses: actions/setup-java@v4 18 | with: 19 | distribution: 'temurin' 20 | java-version: 17 21 | - name: Update Daily Release 22 | run: ./gradlew updateDailyRelease --url="${{ github.event.client_payload.url }}" --checksum="${{ github.event.client_payload.checksum }}" 23 | - name: Create Pull Request 24 | run: ./gradlew createPullRequestDailyRelease 25 | env: 26 | ZAPBOT_TOKEN: ${{ secrets.ZAPBOT_TOKEN }} 27 | -------------------------------------------------------------------------------- /.github/workflows/update-main-release.yml: -------------------------------------------------------------------------------- 1 | name: Update Main Release 2 | 3 | on: 4 | repository_dispatch: 5 | types: 'main-release' 6 | 7 | jobs: 8 | main-release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout 12 | uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 15 | persist-credentials: false 16 | - name: Setup Java 17 | uses: actions/setup-java@v4 18 | with: 19 | distribution: 'temurin' 20 | java-version: 17 21 | - name: Create News Main Release 22 | run: ./gradlew createNewsMainRelease --release="${{ github.event.client_payload.version }}" 23 | - name: Update Main Release 24 | run: ./gradlew updateMainRelease --release="${{ github.event.client_payload.version }}" 25 | - name: Create Pull Request 26 | run: ./gradlew createPullRequestMainRelease 27 | env: 28 | ZAPBOT_TOKEN: ${{ secrets.ZAPBOT_TOKEN }} 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | #------- 3 | .gradle 4 | /build 5 | /buildSrc/build 6 | /buildSrc/.kotlin 7 | 8 | # IDEA 9 | # ---- 10 | .idea 11 | .shelf 12 | /*.iml 13 | /*.ipr 14 | /*.iws 15 | /buildSrc/*.iml 16 | /buildSrc/*.ipr 17 | /buildSrc/*.iws 18 | /buildSrc/out 19 | /out 20 | 21 | # Eclipse 22 | # ------- 23 | *.classpath 24 | *.project 25 | *.settings 26 | /bin 27 | /buildSrc/bin 28 | 29 | # NetBeans 30 | # -------- 31 | .nb-gradle 32 | .nb-gradle-properties -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zap-admin 2 | ZAP Admin 3 | 4 | This project is for 'admin' files like the such as the one ZAP uses for the 'check for updates' call. 5 | -------------------------------------------------------------------------------- /ZapVersions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2.16.1 5 | D-2025-06-16 6 | 7 | https://github.com/zaproxy/zaproxy/releases/download/w2025-06-16/ZAP_WEEKLY_D-2025-06-16.zip 8 | ZAP_WEEKLY_D-2025-06-16.zip 9 | SHA-256:2e4a9db7e0f0f4d325addf789d37496e0955889312e624309c898c4dff17107d 10 | 289372955 11 | 12 | 13 | https://github.com/zaproxy/zaproxy/releases/download/v2.16.1/ZAP_2_16_1_windows-x32.exe 14 | ZAP_2_16_1_windows-x32.exe 15 | SHA-256:8437978b03c88f83933e07319dccb3c958c9db97ef8abc571e56c30938797e1a 16 | 245210624 17 | 18 | 19 | https://github.com/zaproxy/zaproxy/releases/download/v2.16.1/ZAP_2_16_1_windows.exe 20 | ZAP_2_16_1_windows.exe 21 | SHA-256:d9aca657be405d5ac3cc82af576ea71cd9b35894c81e4a8dd696d56a69ce861d 22 | 245386752 23 | 24 | 25 | https://github.com/zaproxy/zaproxy/releases/download/v2.16.1/ZAP_2.16.1_Linux.tar.gz 26 | ZAP_2.16.1_Linux.tar.gz 27 | SHA-256:5b2eb8319b085121a6e8ad50d69d67dbef8c867166f71a937bfc888d247a2ac1 28 | 234364899 29 | 30 | 31 | https://github.com/zaproxy/zaproxy/releases/download/v2.16.1/ZAP_2.16.1.dmg 32 | ZAP_2.16.1.dmg 33 | SHA-256:79d7bc6db7e9583d3d90549791843998f0cf170ed975cfa01fac657f2e0d9120 34 | 262910572 35 | 36 | Bug fix and enhancement release. 37 | https://www.zaproxy.org/docs/desktop/releases/2.16.1/ 38 | 39 | 40 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | id("com.diffplug.spotless") 4 | id("org.zaproxy.common") 5 | } 6 | 7 | repositories { 8 | mavenCentral() 9 | } 10 | 11 | tasks.withType().configureEach { 12 | if (JavaVersion.current().getMajorVersion() >= "21") { 13 | options.compilerArgs = options.compilerArgs + "-Xlint:-this-escape" 14 | } 15 | } 16 | 17 | dependencies { 18 | implementation("commons-configuration:commons-configuration:1.10") 19 | implementation("commons-codec:commons-codec:1.17.1") 20 | 21 | val flexmarkVersion = "0.64.8" 22 | implementation("com.vladsch.flexmark:flexmark-java:$flexmarkVersion") 23 | implementation("com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:$flexmarkVersion") 24 | implementation("com.vladsch.flexmark:flexmark-ext-gfm-tasklist:$flexmarkVersion") 25 | implementation("com.vladsch.flexmark:flexmark-ext-tables:$flexmarkVersion") 26 | implementation("com.vladsch.flexmark:flexmark-ext-yaml-front-matter:$flexmarkVersion") 27 | 28 | implementation("com.vladsch.flexmark:flexmark-html2md-converter:$flexmarkVersion") 29 | implementation("com.vladsch.flexmark:flexmark-ext-anchorlink:$flexmarkVersion") 30 | implementation("com.vladsch.flexmark:flexmark-profile-pegdown:$flexmarkVersion") 31 | 32 | implementation("org.apache.commons:commons-lang3:3.12.0") 33 | val jgitVersion = "7.1.0.202411261347-r" 34 | implementation("org.eclipse.jgit:org.eclipse.jgit:$jgitVersion") 35 | implementation("org.eclipse.jgit:org.eclipse.jgit.archive:$jgitVersion") 36 | implementation("org.kohsuke:github-api:1.326") 37 | // Include annotations used by the above library to avoid compiler warnings. 38 | compileOnly("com.google.code.findbugs:findbugs-annotations:3.0.1") 39 | compileOnly("com.infradna.tool:bridge-method-annotation:1.18") { 40 | exclude(group = "org.jenkins-ci") 41 | } 42 | implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.2") 43 | implementation("org.snakeyaml:snakeyaml-engine:2.6") 44 | implementation("org.zaproxy:zap:2.15.0") 45 | } 46 | 47 | spotless { 48 | kotlin { 49 | ktlint() 50 | } 51 | 52 | kotlinGradle { 53 | ktlint() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /buildSrc/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/AbstractGenerateWebsiteReleaseData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.util.List; 23 | import org.apache.commons.configuration.XMLConfiguration; 24 | import org.gradle.api.DefaultTask; 25 | import org.gradle.api.file.RegularFileProperty; 26 | import org.gradle.api.provider.Property; 27 | import org.gradle.api.tasks.Input; 28 | import org.gradle.api.tasks.InputFile; 29 | import org.gradle.api.tasks.OutputFile; 30 | import org.gradle.api.tasks.TaskAction; 31 | import org.zaproxy.gradle.ReleaseData.ReleaseFile; 32 | 33 | /** An abstract task for generation of release data for the website. */ 34 | public abstract class AbstractGenerateWebsiteReleaseData extends DefaultTask { 35 | 36 | private static final double MEGABYTE = 1024 * 1024; 37 | 38 | public AbstractGenerateWebsiteReleaseData(String releaseName) { 39 | setGroup("ZAP"); 40 | setDescription("Generates the " + releaseName + " release data for the website."); 41 | } 42 | 43 | @InputFile 44 | public abstract RegularFileProperty getZapVersions(); 45 | 46 | @Input 47 | public abstract Property getGeneratedDataComment(); 48 | 49 | @OutputFile 50 | public abstract RegularFileProperty getInto(); 51 | 52 | @TaskAction 53 | public void generate() throws Exception { 54 | XMLConfiguration zapVersionsXml = new CustomXmlConfiguration(); 55 | zapVersionsXml.load(getZapVersions().get().getAsFile()); 56 | 57 | ReleaseData releaseData = new ReleaseData(createReleaseFiles(zapVersionsXml)); 58 | releaseData.save(getInto().get().getAsFile().toPath(), getGeneratedDataComment().get()); 59 | } 60 | 61 | protected abstract List createReleaseFiles(XMLConfiguration zapVersionsXml) 62 | throws Exception; 63 | 64 | protected static String toMegaBytes(String value) { 65 | return toMegaBytes(Long.parseLong(value)); 66 | } 67 | 68 | protected static String toMegaBytes(long value) { 69 | return Math.round(value / MEGABYTE) + " MB"; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/AbstractUpdateZapVersionsEntries.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.util.List; 23 | import org.gradle.api.DefaultTask; 24 | import org.gradle.api.tasks.options.Option; 25 | 26 | /** An abstract task that allows to update {@code ZapVersions.xml} files. */ 27 | public abstract class AbstractUpdateZapVersionsEntries extends DefaultTask 28 | implements UpdateZapVersionsEntries { 29 | 30 | public AbstractUpdateZapVersionsEntries() { 31 | setGroup("ZAP"); 32 | } 33 | 34 | @Option(option = "into", description = "The ZapVersions.xml files to update.") 35 | public void setFiles(List files) { 36 | getInto().setFrom(files); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/AddOnReleaseData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import com.fasterxml.jackson.annotation.JsonInclude; 23 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import com.fasterxml.jackson.databind.ObjectMapper; 26 | import com.fasterxml.jackson.databind.PropertyNamingStrategies; 27 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 28 | import java.io.IOException; 29 | import java.util.List; 30 | 31 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 32 | @JsonInclude(value = Include.NON_NULL) 33 | public class AddOnReleaseData { 34 | 35 | @JsonProperty(value = "addons") 36 | private List addOns; 37 | 38 | public AddOnReleaseData() {} 39 | 40 | public List getAddOns() { 41 | return addOns; 42 | } 43 | 44 | public void setAddOns(List addOns) { 45 | this.addOns = addOns; 46 | } 47 | 48 | public static AddOnReleaseData read(String file) { 49 | try { 50 | return new ObjectMapper().readValue(file, AddOnReleaseData.class); 51 | } catch (IOException e) { 52 | throw new TaskException("Failed to read the add-on release data: " + e.getMessage(), e); 53 | } 54 | } 55 | 56 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 57 | @JsonInclude(value = Include.NON_NULL) 58 | public static class Release { 59 | 60 | private String url; 61 | private String checksum; 62 | 63 | public Release() {} 64 | 65 | public String getUrl() { 66 | return url; 67 | } 68 | 69 | public void setUrl(String url) { 70 | this.url = url; 71 | } 72 | 73 | public String getChecksum() { 74 | return checksum; 75 | } 76 | 77 | public void setChecksum(String checksum) { 78 | this.checksum = checksum; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/CreateNewsMainRelease.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.nio.file.DirectoryStream; 25 | import java.nio.file.Files; 26 | import java.nio.file.Path; 27 | import javax.inject.Inject; 28 | import org.gradle.api.DefaultTask; 29 | import org.gradle.api.file.RegularFileProperty; 30 | import org.gradle.api.provider.Property; 31 | import org.gradle.api.tasks.Input; 32 | import org.gradle.api.tasks.TaskAction; 33 | import org.gradle.api.tasks.options.Option; 34 | import org.gradle.workers.WorkAction; 35 | import org.gradle.workers.WorkParameters; 36 | import org.gradle.workers.WorkQueue; 37 | import org.gradle.workers.WorkerExecutor; 38 | 39 | /** Task that creates news file and entries for main release. */ 40 | public abstract class CreateNewsMainRelease extends DefaultTask { 41 | 42 | private static final String VERSION_TOKEN = "@@VERSION@@"; 43 | 44 | public CreateNewsMainRelease() { 45 | setGroup("ZAP"); 46 | setDescription("Creates news file and news entries for a main release."); 47 | } 48 | 49 | @Input 50 | public abstract Property getPreviousVersion(); 51 | 52 | @Option(option = "release", description = "The main release version.") 53 | public void setReleaseVersion(String version) { 54 | getVersion().set(version); 55 | } 56 | 57 | @Input 58 | public abstract Property getVersion(); 59 | 60 | @Input 61 | public abstract Property getNewsDir(); 62 | 63 | @Input 64 | public abstract Property getItem(); 65 | 66 | @Input 67 | public abstract Property getLink(); 68 | 69 | @Inject 70 | public abstract WorkerExecutor getWorkerExecutor(); 71 | 72 | @TaskAction 73 | public void create() throws Exception { 74 | String currentVersion = getVersion().get(); 75 | Path newsDir = getNewsDir().get().toPath(); 76 | 77 | createNewsFileCurrentVersion(newsDir, currentVersion, getPreviousVersion().get()); 78 | 79 | String item = replaceVersion(getItem().get(), currentVersion); 80 | String link = replaceVersion(getLink().get(), currentVersion); 81 | WorkQueue workQueue = getWorkerExecutor().noIsolation(); 82 | 83 | try (DirectoryStream stream = Files.newDirectoryStream(newsDir)) { 84 | stream.forEach( 85 | file -> 86 | workQueue.submit( 87 | CreateNewsEntry.class, 88 | parameters -> { 89 | parameters.getFile().set(file.toFile()); 90 | parameters.getItem().set(item); 91 | parameters.getLink().set(link); 92 | })); 93 | } 94 | } 95 | 96 | public interface CreateNewsEntryParameters extends WorkParameters { 97 | 98 | RegularFileProperty getFile(); 99 | 100 | Property getItem(); 101 | 102 | Property getLink(); 103 | } 104 | 105 | public abstract static class CreateNewsEntry implements WorkAction { 106 | 107 | private static final String NEWS_KEY = "news."; 108 | private static final String NEWS_ID_KEY = NEWS_KEY + "id"; 109 | private static final String NEWS_DEFAULT_KEY = NEWS_KEY + "default."; 110 | private static final String NEWS_DEFAULT_ITEM_KEY = NEWS_DEFAULT_KEY + "item"; 111 | private static final String NEWS_DEFAULT_LINK_KEY = NEWS_DEFAULT_KEY + "link"; 112 | 113 | @Override 114 | public void execute() { 115 | try { 116 | File file = getParameters().getFile().getAsFile().get(); 117 | CustomXmlConfiguration news = new CustomXmlConfiguration(file); 118 | String id = newNewsId(news.getString(NEWS_ID_KEY, null)); 119 | news.clear(); 120 | news.setProperty(NEWS_ID_KEY, id); 121 | news.setProperty(NEWS_DEFAULT_ITEM_KEY, getParameters().getItem().get()); 122 | news.setProperty(NEWS_DEFAULT_LINK_KEY, getParameters().getLink().get()); 123 | news.save(file); 124 | } catch (Exception e) { 125 | throw new RuntimeException(e); 126 | } 127 | } 128 | 129 | private static String newNewsId(String currentId) { 130 | if (currentId == null || currentId.isEmpty()) { 131 | return "1"; 132 | } 133 | return String.valueOf(Integer.parseInt(currentId) + 1); 134 | } 135 | } 136 | 137 | private static void createNewsFileCurrentVersion( 138 | Path newsDir, String currentVersion, String previousVerion) throws IOException { 139 | Path currentNewsFile = newsDir.resolve(convertToNewsFileName(currentVersion)); 140 | 141 | if (Files.exists(currentNewsFile)) { 142 | return; 143 | } 144 | 145 | Path previousNewsFile = newsDir.resolve(convertToNewsFileName(previousVerion)); 146 | if (Files.exists(previousNewsFile)) { 147 | Files.copy(previousNewsFile, currentNewsFile); 148 | } else { 149 | Files.createFile(currentNewsFile); 150 | } 151 | } 152 | 153 | private static String replaceVersion(String string, String version) { 154 | return string.replace(VERSION_TOKEN, version); 155 | } 156 | 157 | private static String convertToNewsFileName(String version) { 158 | int idx = version.lastIndexOf('.'); 159 | return version.substring(0, idx).replace('.', '_') + ".xml"; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/CreatePullRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import org.gradle.api.DefaultTask; 23 | import org.gradle.api.model.ObjectFactory; 24 | import org.gradle.api.provider.Property; 25 | import org.gradle.api.tasks.Internal; 26 | import org.gradle.api.tasks.TaskAction; 27 | 28 | /** A task that checks for modifications in a git repo, commits, and creates a pull request. */ 29 | public abstract class CreatePullRequest extends DefaultTask { 30 | 31 | private static final String DEFAULT_GIT_BASE_BRANCH_NAME = "master"; 32 | 33 | private final Property baseBranchName; 34 | 35 | public CreatePullRequest() { 36 | ObjectFactory objects = getProject().getObjects(); 37 | this.baseBranchName = 38 | objects.property(String.class).convention(DEFAULT_GIT_BASE_BRANCH_NAME); 39 | 40 | setGroup("ZAP"); 41 | setDescription("Creates a pull request with modifications done in a repo."); 42 | } 43 | 44 | @Internal 45 | public Property getBaseBranchName() { 46 | return baseBranchName; 47 | } 48 | 49 | @Internal 50 | public abstract Property getBranchName(); 51 | 52 | @Internal 53 | public abstract Property getUser(); 54 | 55 | @Internal 56 | public abstract Property getRepo(); 57 | 58 | @Internal 59 | public abstract Property getCommitSummary(); 60 | 61 | @Internal 62 | public abstract Property getCommitDescription(); 63 | 64 | @TaskAction 65 | public void pullRequest() throws Exception { 66 | CreatePullRequestImpl.create( 67 | getRepo().get(), 68 | getUser().get(), 69 | getBranchName().get(), 70 | baseBranchName.get(), 71 | getCommitSummary().get(), 72 | getCommitDescription().get()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/CreatePullRequestImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.File; 23 | import java.util.List; 24 | import org.eclipse.jgit.api.AddCommand; 25 | import org.eclipse.jgit.api.Git; 26 | import org.eclipse.jgit.api.Status; 27 | import org.eclipse.jgit.lib.PersonIdent; 28 | import org.eclipse.jgit.lib.Repository; 29 | import org.eclipse.jgit.storage.file.FileRepositoryBuilder; 30 | import org.eclipse.jgit.transport.URIish; 31 | import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; 32 | import org.kohsuke.github.GHIssueState; 33 | import org.kohsuke.github.GHPullRequest; 34 | import org.kohsuke.github.GHRepository; 35 | import org.kohsuke.github.GitHub; 36 | 37 | public class CreatePullRequestImpl { 38 | 39 | public static final String GITHUB_BASE_URL = "https://github.com/"; 40 | 41 | private static final String GIT_REMOTE_ORIGIN = "origin"; 42 | 43 | public static void create( 44 | GitHubRepo ghRepo, 45 | GitHubUser ghUser, 46 | String branchName, 47 | String baseBranchName, 48 | String commitSummary, 49 | String commitDescription) 50 | throws Exception { 51 | Repository repository = 52 | new FileRepositoryBuilder().setGitDir(new File(ghRepo.getDir(), ".git")).build(); 53 | try (Git git = new Git(repository)) { 54 | Status status = git.status().call(); 55 | if (!status.hasUncommittedChanges() && status.getUntracked().isEmpty()) { 56 | return; 57 | } 58 | 59 | URIish originUri = 60 | new URIish(GITHUB_BASE_URL + ghUser.getName() + "/" + ghRepo.getName()); 61 | git.remoteSetUrl().setRemoteName(GIT_REMOTE_ORIGIN).setRemoteUri(originUri).call(); 62 | 63 | git.checkout() 64 | .setCreateBranch(true) 65 | .setName(branchName) 66 | .setStartPoint(GIT_REMOTE_ORIGIN + "/" + baseBranchName) 67 | .call(); 68 | 69 | if (!status.getUntracked().isEmpty()) { 70 | AddCommand add = git.add(); 71 | status.getUntracked().forEach(add::addFilepattern); 72 | add.call(); 73 | } 74 | 75 | PersonIdent personIdent = new PersonIdent(ghUser.getName(), ghUser.getEmail()); 76 | git.commit() 77 | .setAll(true) 78 | .setSign(false) 79 | .setAuthor(personIdent) 80 | .setCommitter(personIdent) 81 | .setMessage( 82 | commitSummary + "\n\n" + commitDescription + signedOffBy(personIdent)) 83 | .call(); 84 | 85 | git.push() 86 | .setCredentialsProvider( 87 | new UsernamePasswordCredentialsProvider( 88 | ghUser.getName(), ghUser.getAuthToken())) 89 | .setForce(true) 90 | .add(branchName) 91 | .call(); 92 | 93 | GHRepository ghRepository = 94 | GitHub.connect(ghUser.getName(), ghUser.getAuthToken()) 95 | .getRepository(ghRepo.toString()); 96 | 97 | List pulls = 98 | ghRepository 99 | .queryPullRequests() 100 | .base(baseBranchName) 101 | .head(ghUser.getName() + ":" + branchName) 102 | .state(GHIssueState.OPEN) 103 | .list() 104 | .toList(); 105 | if (pulls.isEmpty()) { 106 | ghRepository.createPullRequest( 107 | commitSummary, 108 | ghUser.getName() + ":" + branchName, 109 | baseBranchName, 110 | commitDescription); 111 | } else { 112 | pulls.get(0).setBody(commitDescription); 113 | } 114 | } 115 | } 116 | 117 | private static String signedOffBy(PersonIdent personIdent) { 118 | return "\n\nSigned-off-by: " 119 | + personIdent.getName() 120 | + " <" 121 | + personIdent.getEmailAddress() 122 | + ">"; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/CustomXmlConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2018 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.File; 23 | import java.io.InputStream; 24 | import java.io.Reader; 25 | import javax.xml.transform.Transformer; 26 | import javax.xml.transform.TransformerException; 27 | import org.apache.commons.configuration.ConfigurationException; 28 | import org.apache.commons.configuration.XMLConfiguration; 29 | 30 | public class CustomXmlConfiguration extends XMLConfiguration { 31 | 32 | private static final long serialVersionUID = 7018390148134058207L; 33 | 34 | public CustomXmlConfiguration() { 35 | setEncoding("UTF-8"); 36 | setDelimiterParsingDisabled(true); 37 | setRootElementName("ZAP"); 38 | } 39 | 40 | public CustomXmlConfiguration(File file) throws ConfigurationException { 41 | this(); 42 | load(file); 43 | } 44 | 45 | @Override 46 | protected Transformer createTransformer() throws TransformerException { 47 | Transformer transformer = super.createTransformer(); 48 | transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); 49 | return transformer; 50 | } 51 | 52 | @Override 53 | public void load(InputStream in) throws ConfigurationException { 54 | super.load(in); 55 | postLoad(); 56 | } 57 | 58 | @Override 59 | public void load(Reader in) throws ConfigurationException { 60 | super.load(in); 61 | postLoad(); 62 | } 63 | 64 | private void postLoad() { 65 | // Ensure it's used a "clean" document for proper indentation of the configurations. 66 | // In newer Java versions (9+) the text nodes are indented as well, which would lead 67 | // to additional text nodes each time the configuration is loaded/saved. 68 | clearReferences(getRootNode()); 69 | String rootName = getRootElementName(); 70 | getDocument().removeChild(getDocument().getDocumentElement()); 71 | getDocument().appendChild(getDocument().createElement(rootName)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/DownloadReleasedAddOns.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.nio.file.Path; 23 | import java.util.List; 24 | import java.util.Set; 25 | import org.gradle.api.DefaultTask; 26 | import org.gradle.api.file.DirectoryProperty; 27 | import org.gradle.api.file.RegularFileProperty; 28 | import org.gradle.api.tasks.InputFile; 29 | import org.gradle.api.tasks.OutputDirectory; 30 | import org.gradle.api.tasks.TaskAction; 31 | import org.zaproxy.zap.utils.ZapXmlConfiguration; 32 | 33 | /** A task that downloads the add-ons released in the last commit, if any. */ 34 | public abstract class DownloadReleasedAddOns extends DefaultTask { 35 | 36 | private static final String ADDON_ELEMENT_PREFIX = "addon_"; 37 | private static final String URL_ELEMENT = ".url"; 38 | private static final String HASH_ELEMENT = ".hash"; 39 | 40 | @InputFile 41 | public abstract RegularFileProperty getReleaseState(); 42 | 43 | @InputFile 44 | public abstract RegularFileProperty getZapVersions(); 45 | 46 | @InputFile 47 | public abstract RegularFileProperty getAllowedAddOns(); 48 | 49 | @OutputDirectory 50 | public abstract DirectoryProperty getOutputDir(); 51 | 52 | @TaskAction 53 | void downloadAddOns() throws Exception { 54 | ReleaseState releaseState = ReleaseState.read(getReleaseState().getAsFile().get()); 55 | List addOns = releaseState.getAddOns(); 56 | if (addOns == null || addOns.isEmpty()) { 57 | return; 58 | } 59 | 60 | Set allowedAddOns = TaskUtils.readAllowedAddOns(getAllowedAddOns()); 61 | Path outputDir = getOutputDir().getAsFile().get().toPath(); 62 | ZapXmlConfiguration zapVersions = 63 | new ZapXmlConfiguration(getZapVersions().getAsFile().get()); 64 | for (ReleaseState.AddOnChange addOn : addOns) { 65 | String addOnId = addOn.getId(); 66 | if (!addOn.isNewVersion() || !allowedAddOns.contains(addOnId)) { 67 | continue; 68 | } 69 | 70 | try { 71 | String url = getString(zapVersions, addOnId, URL_ELEMENT); 72 | String[] checksumData = getString(zapVersions, addOnId, HASH_ELEMENT).split(":", 2); 73 | String checksumAlgorithm = checksumData[0]; 74 | String checksum = checksumData[1]; 75 | Path downloadedAddOn = TaskUtils.downloadAddOn(this, url, outputDir); 76 | TaskUtils.calculateChecksum(downloadedAddOn, checksumAlgorithm, checksum); 77 | } catch (Exception e) { 78 | getLogger() 79 | .error( 80 | "Failed to download the add-on {}. Cause: {}", 81 | addOnId, 82 | e.getMessage(), 83 | e); 84 | } 85 | } 86 | } 87 | 88 | private static String getString( 89 | ZapXmlConfiguration zapVersions, String addOnId, String element) { 90 | return zapVersions.getString(ADDON_ELEMENT_PREFIX + addOnId + element); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/GenerateWebsiteAddonsData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.BufferedWriter; 23 | import java.io.File; 24 | import java.net.URL; 25 | import java.nio.charset.Charset; 26 | import java.nio.file.Files; 27 | import java.util.ArrayList; 28 | import java.util.LinkedHashMap; 29 | import java.util.List; 30 | import java.util.Map; 31 | import org.gradle.api.DefaultTask; 32 | import org.gradle.api.file.RegularFileProperty; 33 | import org.gradle.api.provider.Property; 34 | import org.gradle.api.tasks.Input; 35 | import org.gradle.api.tasks.InputFile; 36 | import org.gradle.api.tasks.OutputFile; 37 | import org.gradle.api.tasks.TaskAction; 38 | import org.snakeyaml.engine.v2.api.Dump; 39 | import org.snakeyaml.engine.v2.api.DumpSettings; 40 | import org.snakeyaml.engine.v2.common.FlowStyle; 41 | import org.zaproxy.zap.control.AddOn; 42 | import org.zaproxy.zap.control.AddOnCollection; 43 | import org.zaproxy.zap.utils.ZapXmlConfiguration; 44 | 45 | public abstract class GenerateWebsiteAddonsData extends DefaultTask { 46 | 47 | private static final DumpSettings SETTINGS = 48 | DumpSettings.builder().setDefaultFlowStyle(FlowStyle.BLOCK).build(); 49 | private static final Dump DUMP = new Dump(SETTINGS); 50 | 51 | public GenerateWebsiteAddonsData() { 52 | setGroup("ZAP"); 53 | setDescription("Generates the add-ons data for the website."); 54 | } 55 | 56 | @OutputFile 57 | public abstract RegularFileProperty getInto(); 58 | 59 | @InputFile 60 | public abstract RegularFileProperty getZapVersions(); 61 | 62 | @Input 63 | public abstract Property getGeneratedDataComment(); 64 | 65 | @Input 66 | public abstract Property getWebsiteUrl(); 67 | 68 | @TaskAction 69 | public void update() throws Exception { 70 | File xmlFile = getZapVersions().get().getAsFile(); 71 | if (xmlFile.exists()) { 72 | List> addOnList = new ArrayList<>(); 73 | ZapXmlConfiguration conf = new ZapXmlConfiguration(xmlFile); 74 | AddOnCollection aoc = new AddOnCollection(conf, AddOnCollection.Platform.linux); 75 | for (AddOn addOn : aoc.getAddOns()) { 76 | Map addOnData = new LinkedHashMap<>(); 77 | addOnData.put("id", addOn.getId()); 78 | addOnData.put("name", addOn.getName()); 79 | addOnData.put("description", addOn.getDescription()); 80 | addOnData.put("author", addOn.getAuthor()); 81 | addOnData.put("status", addOn.getStatus().name()); 82 | addOnData.put("infoUrl", getUrl(addOn.getInfo(), getWebsiteUrl().get())); 83 | addOnData.put("repoUrl", getUrl(addOn.getRepo(), getWebsiteUrl().get())); 84 | addOnData.put("downloadUrl", addOn.getUrl().toString()); 85 | addOnData.put("date", conf.getString("addon_" + addOn.getId() + ".date")); 86 | addOnData.put( 87 | "version", 88 | convertVersion(conf.getString("addon_" + addOn.getId() + ".version"))); 89 | addOnList.add(addOnData); 90 | } 91 | 92 | String output = DUMP.dumpToString(addOnList); 93 | 94 | try (BufferedWriter writer = 95 | Files.newBufferedWriter( 96 | getInto().get().getAsFile().toPath(), Charset.defaultCharset())) { 97 | writer.write(getGeneratedDataComment().get()); 98 | writer.write("\n---\n"); 99 | writer.write(output); 100 | } 101 | } else { 102 | System.out.print("File not found!"); 103 | } 104 | } 105 | 106 | private static Object convertVersion(String version) { 107 | return version.contains(".") ? version : Integer.valueOf(version); 108 | } 109 | 110 | private static String getUrl(URL url, String websiteUrl) { 111 | if (url == null) { 112 | return ""; 113 | } 114 | 115 | String strUrl = url.toString(); 116 | if (strUrl.startsWith(websiteUrl)) { 117 | return strUrl.substring(websiteUrl.length() - 1); 118 | } 119 | return strUrl; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/GenerateWebsiteMainReleaseData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.IOException; 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | import java.util.NoSuchElementException; 26 | import java.util.Optional; 27 | import org.apache.commons.configuration.XMLConfiguration; 28 | import org.gradle.api.provider.Property; 29 | import org.gradle.api.tasks.Internal; 30 | import org.kohsuke.github.GHAsset; 31 | import org.kohsuke.github.GHRepository; 32 | import org.kohsuke.github.GitHub; 33 | import org.zaproxy.gradle.ReleaseData.ReleaseFile; 34 | 35 | /** A task that generates the main release data for the website. */ 36 | public abstract class GenerateWebsiteMainReleaseData extends AbstractGenerateWebsiteReleaseData { 37 | 38 | private static final String CORE_VERSION_ELEMENT = "core.version"; 39 | private static final String TAG_PREFIX = "v"; 40 | 41 | public GenerateWebsiteMainReleaseData() { 42 | super("main"); 43 | 44 | // Execute always, in case release assets have changed. 45 | getOutputs().upToDateWhen(task -> false); 46 | } 47 | 48 | @Internal 49 | public abstract Property getGitHubUser(); 50 | 51 | @Internal 52 | public abstract Property getGitHubRepo(); 53 | 54 | @Override 55 | protected List createReleaseFiles(XMLConfiguration zapVersionsXml) 56 | throws IOException { 57 | GitHubUser user = getGitHubUser().get(); 58 | GHRepository repo = 59 | createGitHubConnection(user.getName(), user.getAuthToken()) 60 | .getRepository(getGitHubRepo().get().toString()); 61 | 62 | String version = zapVersionsXml.getString(CORE_VERSION_ELEMENT); 63 | List assets = repo.getReleaseByTagName(TAG_PREFIX + version).listAssets().toList(); 64 | 65 | List releaseFiles = new ArrayList<>(); 66 | 67 | GHAsset asset = getAsset(assets, "windows.exe"); 68 | releaseFiles.add( 69 | new ReleaseFile( 70 | "Windows (64) Installer", 71 | "win-64-i", 72 | toMegaBytes(asset.getSize()), 73 | asset.getBrowserDownloadUrl())); 74 | 75 | asset = getAsset(assets, "windows-x32.exe"); 76 | releaseFiles.add( 77 | new ReleaseFile( 78 | "Windows (32) Installer", 79 | "win-32-i", 80 | toMegaBytes(asset.getSize()), 81 | asset.getBrowserDownloadUrl())); 82 | 83 | asset = getAsset(assets, "unix.sh"); 84 | releaseFiles.add( 85 | new ReleaseFile( 86 | "Linux Installer", 87 | "nix-i", 88 | toMegaBytes(asset.getSize()), 89 | asset.getBrowserDownloadUrl())); 90 | 91 | asset = getAsset(assets, "Linux.tar.gz"); 92 | releaseFiles.add( 93 | new ReleaseFile( 94 | "Linux Package", 95 | "nix-p", 96 | toMegaBytes(asset.getSize()), 97 | asset.getBrowserDownloadUrl())); 98 | 99 | asset = getAsset(assets, version + ".dmg"); 100 | releaseFiles.add( 101 | new ReleaseFile( 102 | "macOS (Intel - amd64) Installer", 103 | "osx-i", 104 | toMegaBytes(asset.getSize()), 105 | asset.getBrowserDownloadUrl())); 106 | 107 | Optional optionalAsset = getOptionalAsset(assets, "_aarch64.dmg"); 108 | if (optionalAsset.isPresent()) { 109 | asset = optionalAsset.get(); 110 | releaseFiles.add( 111 | new ReleaseFile( 112 | "macOS (Apple Silicon - aarch64) Installer", 113 | "osx-aarch64-i", 114 | toMegaBytes(asset.getSize()), 115 | asset.getBrowserDownloadUrl())); 116 | } 117 | 118 | asset = getAsset(assets, "Crossplatform.zip"); 119 | releaseFiles.add( 120 | new ReleaseFile( 121 | "Cross Platform Package", 122 | "cp-p", 123 | toMegaBytes(asset.getSize()), 124 | asset.getBrowserDownloadUrl())); 125 | 126 | asset = getAsset(assets, "Core.zip"); 127 | releaseFiles.add( 128 | new ReleaseFile( 129 | "Core Cross Platform Package", 130 | "cp-c", 131 | toMegaBytes(asset.getSize()), 132 | asset.getBrowserDownloadUrl())); 133 | 134 | return releaseFiles; 135 | } 136 | 137 | private GHAsset getAsset(List assets, String suffix) { 138 | return getOptionalAsset(assets, suffix) 139 | .orElseThrow(() -> new NoSuchElementException("No asset with suffix: " + suffix)); 140 | } 141 | 142 | private Optional getOptionalAsset(List assets, String suffix) { 143 | return assets.stream().filter(asset -> asset.getName().endsWith(suffix)).findFirst(); 144 | } 145 | 146 | private GitHub createGitHubConnection(String userName, String authToken) throws IOException { 147 | if (authToken == null || authToken.isEmpty()) { 148 | return GitHub.connectAnonymously(); 149 | } 150 | return GitHub.connect(userName, authToken); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/GenerateWebsiteSbomPages.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2023 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.IOException; 23 | import java.nio.file.Files; 24 | import java.nio.file.Path; 25 | import java.util.List; 26 | import org.gradle.api.DefaultTask; 27 | import org.gradle.api.file.DirectoryProperty; 28 | import org.gradle.api.file.RegularFileProperty; 29 | import org.gradle.api.tasks.InputFile; 30 | import org.gradle.api.tasks.OutputDirectory; 31 | import org.gradle.api.tasks.TaskAction; 32 | import org.zaproxy.gradle.website.WebsiteSbomPageGenerator; 33 | import org.zaproxy.zap.utils.ZapXmlConfiguration; 34 | 35 | public abstract class GenerateWebsiteSbomPages extends DefaultTask { 36 | 37 | private static final String ADDON_ELEMENT_PREFIX = "addon_"; 38 | private static final String URL_ELEMENT = ".url"; 39 | private static final String NAME_ELEMENT = ".name"; 40 | 41 | @InputFile 42 | public abstract RegularFileProperty getReleaseState(); 43 | 44 | @InputFile 45 | public abstract RegularFileProperty getZapVersions(); 46 | 47 | @OutputDirectory 48 | public abstract DirectoryProperty getOutputDir(); 49 | 50 | @TaskAction 51 | public void generate() throws Exception { 52 | ReleaseState releaseState = ReleaseState.read(getReleaseState().getAsFile().get()); 53 | List addOns = releaseState.getAddOns(); 54 | if (addOns == null || addOns.isEmpty()) { 55 | return; 56 | } 57 | 58 | Path outputDir = getOutputDir().getAsFile().get().toPath(); 59 | ZapXmlConfiguration zapVersions = 60 | new ZapXmlConfiguration(getZapVersions().getAsFile().get()); 61 | 62 | for (ReleaseState.AddOnChange addOn : addOns) { 63 | if (!addOn.isNewVersion()) { 64 | continue; 65 | } 66 | String addOnId = addOn.getId(); 67 | String url = getString(zapVersions, addOnId, URL_ELEMENT); 68 | if (!url.startsWith("https://github.com/zaproxy/zap-extensions")) { 69 | continue; 70 | } 71 | 72 | String bomUrl = url.substring(0, url.lastIndexOf("/")) + "/bom.json"; 73 | Path bomPath = getTemporaryDir().toPath().resolve(addOnId + ".cdx.json"); 74 | try { 75 | TaskUtils.downloadFile(this, bomUrl, bomPath); 76 | } catch (Exception e) { 77 | getLogger().warn(e.getMessage(), e); 78 | continue; 79 | } 80 | 81 | String pageTitle = getString(zapVersions, addOnId, NAME_ELEMENT) + " Add-on SBOM"; 82 | Path bomPageOutputPath = outputDir.resolve(Path.of("docs", "sbom", addOnId + ".md")); 83 | Files.createDirectories(bomPageOutputPath.getParent()); 84 | WebsiteSbomPageGenerator.generate( 85 | bomPath, 86 | bomUrl, 87 | pageTitle, 88 | addOnId, 89 | addOn.getCurrentVersion(), 90 | outputDir.resolve(bomPageOutputPath)); 91 | } 92 | } 93 | 94 | private static String getString( 95 | ZapXmlConfiguration zapVersions, String addOnId, String element) { 96 | return zapVersions.getString(ADDON_ELEMENT_PREFIX + addOnId + element); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/GenerateWebsiteWeeklyReleaseData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.util.Collections; 23 | import java.util.List; 24 | import org.apache.commons.configuration.XMLConfiguration; 25 | import org.zaproxy.gradle.ReleaseData.ReleaseFile; 26 | 27 | /** A task that generates the weekly release data for the website. */ 28 | public abstract class GenerateWebsiteWeeklyReleaseData extends AbstractGenerateWebsiteReleaseData { 29 | 30 | private static final String DAILY_ELEMENT = "core.daily"; 31 | private static final String DAILY_SIZE_ELEMENT = DAILY_ELEMENT + ".size"; 32 | private static final String DAILY_URL_ELEMENT = DAILY_ELEMENT + ".url"; 33 | 34 | public GenerateWebsiteWeeklyReleaseData() { 35 | super("weekly"); 36 | } 37 | 38 | @Override 39 | protected List createReleaseFiles(XMLConfiguration zapVersionsXml) { 40 | return Collections.singletonList( 41 | new ReleaseFile( 42 | "Weekly Cross Platform Package", 43 | "cp-p", 44 | toMegaBytes(zapVersionsXml.getString(DAILY_SIZE_ELEMENT)), 45 | zapVersionsXml.getString(DAILY_URL_ELEMENT))); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/HandleMainRelease.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import org.gradle.api.file.RegularFileProperty; 23 | import org.gradle.api.tasks.InputFile; 24 | import org.zaproxy.gradle.ReleaseState.VersionChange; 25 | 26 | /** 27 | * Task that handles a main release, if any. 28 | * 29 | *

Sends a repository dispatch to release the main Docker images. 30 | */ 31 | public abstract class HandleMainRelease extends SendRepositoryDispatch { 32 | 33 | @InputFile 34 | public abstract RegularFileProperty getReleaseState(); 35 | 36 | @Override 37 | void send() { 38 | ReleaseState releaseState = ReleaseState.read(getReleaseState().getAsFile().get()); 39 | if (isNewMainRelease(releaseState)) { 40 | super.send(); 41 | } 42 | } 43 | 44 | private static boolean isNewMainRelease(ReleaseState releaseState) { 45 | VersionChange mainRelease = releaseState.getMainRelease(); 46 | return mainRelease != null && mainRelease.isNewVersion(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/HandleWeeklyRelease.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import org.gradle.api.file.RegularFileProperty; 23 | import org.gradle.api.tasks.InputFile; 24 | import org.zaproxy.gradle.ReleaseState.VersionChange; 25 | 26 | /** 27 | * Task that handles a weekly release, if any. 28 | * 29 | *

Sends a repository dispatch to release the Docker weekly image. 30 | */ 31 | public abstract class HandleWeeklyRelease extends SendRepositoryDispatch { 32 | 33 | @InputFile 34 | public abstract RegularFileProperty getReleaseState(); 35 | 36 | @Override 37 | void send() { 38 | ReleaseState releaseState = ReleaseState.read(getReleaseState().getAsFile().get()); 39 | if (isNewWeeklyRelease(releaseState)) { 40 | super.send(); 41 | } 42 | } 43 | 44 | private static boolean isNewWeeklyRelease(ReleaseState releaseState) { 45 | VersionChange weeklyRelease = releaseState.getWeeklyRelease(); 46 | return weeklyRelease != null && weeklyRelease.isNewVersion(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/ReleaseData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.IOException; 23 | import java.io.UncheckedIOException; 24 | import java.io.Writer; 25 | import java.nio.file.Files; 26 | import java.nio.file.Path; 27 | import java.util.ArrayList; 28 | import java.util.List; 29 | import org.snakeyaml.engine.v2.api.Dump; 30 | import org.snakeyaml.engine.v2.api.DumpSettings; 31 | import org.snakeyaml.engine.v2.api.RepresentToNode; 32 | import org.snakeyaml.engine.v2.api.StreamDataWriter; 33 | import org.snakeyaml.engine.v2.common.FlowStyle; 34 | import org.snakeyaml.engine.v2.nodes.MappingNode; 35 | import org.snakeyaml.engine.v2.nodes.Node; 36 | import org.snakeyaml.engine.v2.nodes.NodeTuple; 37 | import org.snakeyaml.engine.v2.nodes.ScalarNode; 38 | import org.snakeyaml.engine.v2.nodes.Tag; 39 | import org.snakeyaml.engine.v2.representer.StandardRepresenter; 40 | 41 | class ReleaseData { 42 | 43 | private static final DumpSettings SETTINGS = 44 | DumpSettings.builder().setDefaultFlowStyle(FlowStyle.BLOCK).build(); 45 | private static final Dump DUMP = new Dump(SETTINGS, new ReleaseFileRepresenter(SETTINGS)); 46 | 47 | private final List releaseFiles; 48 | 49 | public ReleaseData(List releaseFiles) { 50 | this.releaseFiles = new ArrayList<>(releaseFiles); 51 | } 52 | 53 | public void save(Path file, String comment) throws IOException { 54 | try (Writer writer = Files.newBufferedWriter(file)) { 55 | writer.write(comment); 56 | writer.write("\n---\n"); 57 | DUMP.dump(releaseFiles, new StreamDataWriterAdapter(writer)); 58 | } catch (UncheckedIOException e) { 59 | throw new IOException("Failed to save to: " + file, e.getCause()); 60 | } 61 | } 62 | 63 | static class ReleaseFile { 64 | private final String name; 65 | private final String id; 66 | private final String size; 67 | private final String link; 68 | 69 | ReleaseFile(String name, String id, String size, String link) { 70 | this.name = name; 71 | this.id = id; 72 | this.size = size; 73 | this.link = link; 74 | } 75 | } 76 | 77 | private static class ReleaseFileRepresenter extends StandardRepresenter { 78 | 79 | ReleaseFileRepresenter(DumpSettings settings) { 80 | super(settings); 81 | this.representers.put(ReleaseFile.class, new RepresentReleaseFile()); 82 | } 83 | 84 | private class RepresentReleaseFile implements RepresentToNode { 85 | 86 | @Override 87 | public Node representData(Object data) { 88 | ReleaseFile releaseFile = (ReleaseFile) data; 89 | List nodeData = new ArrayList<>(4); 90 | MappingNode node = 91 | new MappingNode(Tag.MAP, nodeData, settings.getDefaultFlowStyle()); 92 | nodeData.add(new NodeTuple(string("name"), string(releaseFile.name))); 93 | nodeData.add(new NodeTuple(string("id"), string(releaseFile.id))); 94 | nodeData.add(new NodeTuple(string("size"), string(releaseFile.size))); 95 | nodeData.add(new NodeTuple(string("link"), string(releaseFile.link))); 96 | return node; 97 | } 98 | 99 | private ScalarNode string(String value) { 100 | return new ScalarNode(Tag.STR, value, settings.getDefaultScalarStyle()); 101 | } 102 | } 103 | } 104 | 105 | private static class StreamDataWriterAdapter implements StreamDataWriter { 106 | 107 | private final Writer writer; 108 | 109 | StreamDataWriterAdapter(Writer writer) { 110 | this.writer = writer; 111 | } 112 | 113 | @Override 114 | public void write(String str) { 115 | processIoAction(() -> writer.write(str)); 116 | } 117 | 118 | @Override 119 | public void write(String str, int off, int len) { 120 | processIoAction(() -> writer.write(str, off, len)); 121 | } 122 | 123 | @Override 124 | public void flush() { 125 | processIoAction(writer::flush); 126 | } 127 | 128 | private static void processIoAction(IoAction action) { 129 | try { 130 | action.apply(); 131 | } catch (IOException e) { 132 | throw new UncheckedIOException(e); 133 | } 134 | } 135 | } 136 | 137 | private interface IoAction { 138 | void apply() throws IOException; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/ReleaseState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import com.fasterxml.jackson.annotation.JsonInclude; 23 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 24 | import com.fasterxml.jackson.annotation.JsonProperty; 25 | import com.fasterxml.jackson.databind.ObjectMapper; 26 | import com.fasterxml.jackson.databind.PropertyNamingStrategies; 27 | import com.fasterxml.jackson.databind.annotation.JsonNaming; 28 | import java.io.File; 29 | import java.io.IOException; 30 | import java.util.List; 31 | 32 | /** The release state computed from {@code ZapVersions.xml} files. */ 33 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 34 | @JsonInclude(value = Include.NON_NULL) 35 | public class ReleaseState { 36 | 37 | @JsonProperty private VersionChange mainRelease; 38 | @JsonProperty private VersionChange weeklyRelease; 39 | 40 | @JsonProperty private List addOns; 41 | 42 | public ReleaseState() {} 43 | 44 | public VersionChange getMainRelease() { 45 | return mainRelease; 46 | } 47 | 48 | public void setMainRelease(VersionChange mainRelease) { 49 | this.mainRelease = mainRelease; 50 | } 51 | 52 | public VersionChange getWeeklyRelease() { 53 | return weeklyRelease; 54 | } 55 | 56 | public void setWeeklyRelease(VersionChange weeklyRelease) { 57 | this.weeklyRelease = weeklyRelease; 58 | } 59 | 60 | public void setAddOns(List addOns) { 61 | this.addOns = addOns; 62 | } 63 | 64 | public List getAddOns() { 65 | return addOns; 66 | } 67 | 68 | /** 69 | * Writes this {@code ReleaseState} to the given file. 70 | * 71 | * @param file the file to write the release state. 72 | * @throws TaskException if an error occurred while writing the release state. 73 | */ 74 | public void write(File file) { 75 | try { 76 | new ObjectMapper().writeValue(file, this); 77 | } catch (IOException e) { 78 | throw new TaskException("Failed to write the release state: " + e.getMessage(), e); 79 | } 80 | } 81 | 82 | /** 83 | * Reads a {@code ReleaseState} from the given file. 84 | * 85 | * @param file the file with the release state. 86 | * @return a new {@code ReleaseState} with the contents from the file. 87 | * @throws TaskException if an error occurred while reading the release state. 88 | */ 89 | public static ReleaseState read(File file) { 90 | try { 91 | return new ObjectMapper().readValue(file, ReleaseState.class); 92 | } catch (IOException e) { 93 | throw new TaskException("Failed to read the release state: " + e.getMessage(), e); 94 | } 95 | } 96 | 97 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 98 | @JsonInclude(value = Include.NON_EMPTY) 99 | public static class VersionChange { 100 | 101 | @JsonProperty private String previousVersion; 102 | 103 | @JsonProperty private String currentVersion; 104 | 105 | @JsonProperty private boolean newVersion; 106 | 107 | public VersionChange() {} 108 | 109 | public VersionChange(String previousVersion, String currentVersion) { 110 | this.previousVersion = previousVersion; 111 | this.currentVersion = currentVersion; 112 | this.newVersion = previousVersion == null || !previousVersion.equals(currentVersion); 113 | } 114 | 115 | public boolean isNewVersion() { 116 | return newVersion; 117 | } 118 | 119 | public String getPreviousVersion() { 120 | return previousVersion; 121 | } 122 | 123 | public void setPreviousVersion(String previousVersion) { 124 | this.previousVersion = previousVersion; 125 | } 126 | 127 | public String getCurrentVersion() { 128 | return currentVersion; 129 | } 130 | 131 | public void setCurrentVersion(String currentVersion) { 132 | this.currentVersion = currentVersion; 133 | } 134 | } 135 | 136 | @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) 137 | @JsonInclude(value = Include.NON_EMPTY) 138 | public static class AddOnChange extends VersionChange { 139 | 140 | @JsonProperty private String id; 141 | 142 | public AddOnChange() {} 143 | 144 | public AddOnChange(String id, String previousVersion, String currentVersion) { 145 | super(previousVersion, currentVersion); 146 | this.id = id; 147 | } 148 | 149 | public String getId() { 150 | return id; 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/SendRepositoryDispatch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import com.fasterxml.jackson.core.JsonProcessingException; 23 | import com.fasterxml.jackson.databind.ObjectMapper; 24 | import java.io.IOException; 25 | import java.io.OutputStream; 26 | import java.net.HttpURLConnection; 27 | import java.net.ProtocolException; 28 | import java.net.URI; 29 | import java.nio.charset.StandardCharsets; 30 | import java.util.Base64; 31 | import java.util.LinkedHashMap; 32 | import java.util.Map; 33 | import org.apache.commons.io.IOUtils; 34 | import org.gradle.api.DefaultTask; 35 | import org.gradle.api.provider.MapProperty; 36 | import org.gradle.api.provider.Property; 37 | import org.gradle.api.tasks.Input; 38 | import org.gradle.api.tasks.Optional; 39 | import org.gradle.api.tasks.TaskAction; 40 | 41 | /** A task that sends a {@code repository_dispatch} to a GitHub repo. */ 42 | public abstract class SendRepositoryDispatch extends DefaultTask { 43 | 44 | private static final int EXPECTED_STATUS_CODE = HttpURLConnection.HTTP_NO_CONTENT; 45 | private static final int NO_STATUS_CODE = -1; 46 | 47 | @Input 48 | public abstract Property getGitHubUser(); 49 | 50 | @Input 51 | public abstract Property getGitHubRepo(); 52 | 53 | @Input 54 | public abstract Property getEventType(); 55 | 56 | @Input 57 | @Optional 58 | public abstract MapProperty getClientPayload(); 59 | 60 | @TaskAction 61 | void send() { 62 | HttpURLConnection connection = createConnection(); 63 | writeRepositoryDispatch(connection); 64 | 65 | int statusCode = getStatusCode(connection); 66 | if (statusCode == EXPECTED_STATUS_CODE) { 67 | return; 68 | } 69 | 70 | if (statusCode == NO_STATUS_CODE) { 71 | throw new TaskException("Unable to get a response."); 72 | } 73 | 74 | StringBuilder errorMessage = new StringBuilder(); 75 | errorMessage.append( 76 | String.format( 77 | "Repository dispatch was not successful, expected status code %s received %s.", 78 | EXPECTED_STATUS_CODE, statusCode)); 79 | 80 | String response = readResponse(connection); 81 | if (response != null && !response.isEmpty()) { 82 | errorMessage.append("\nResponse:\n").append(response); 83 | } 84 | throw new TaskException(errorMessage.toString()); 85 | } 86 | 87 | private HttpURLConnection createConnection() { 88 | String url = 89 | String.format("https://api.github.com/repos/%s/dispatches", getGitHubRepo().get()); 90 | HttpURLConnection connection; 91 | try { 92 | connection = (HttpURLConnection) new URI(url).toURL().openConnection(); 93 | } catch (Exception e) { 94 | throw new TaskException("Failed to create the connection:", e); 95 | } 96 | connection.setDoOutput(true); 97 | connection.setUseCaches(false); 98 | try { 99 | connection.setRequestMethod("POST"); 100 | } catch (ProtocolException e) { 101 | throw new TaskException("Failed to create the connection:", e); 102 | } 103 | connection.setRequestProperty("Accept", "application/vnd.github.v3+json"); 104 | connection.setRequestProperty("Content-Type", "application/json"); 105 | 106 | GitHubUser user = getGitHubUser().get(); 107 | String userName = user.getName(); 108 | String token = user.getAuthToken(); 109 | byte[] usernameAuthToken = (userName + ":" + token).getBytes(StandardCharsets.UTF_8); 110 | String authorization = "Basic " + Base64.getEncoder().encodeToString(usernameAuthToken); 111 | connection.setRequestProperty("Authorization", authorization); 112 | 113 | return connection; 114 | } 115 | 116 | private void writeRepositoryDispatch(HttpURLConnection connection) { 117 | byte[] repositoryDispatch; 118 | try { 119 | repositoryDispatch = createRepositoryDispatch(); 120 | } catch (JsonProcessingException e) { 121 | throw new TaskException("Failed to create the request body:", e); 122 | } 123 | 124 | try (OutputStream os = connection.getOutputStream()) { 125 | os.write(repositoryDispatch); 126 | } catch (IOException e) { 127 | throw new TaskException("Failed to write the repository dispatch:", e); 128 | } 129 | } 130 | 131 | private byte[] createRepositoryDispatch() throws JsonProcessingException { 132 | Map repositoryDispatch = new LinkedHashMap<>(); 133 | repositoryDispatch.put("event_type", getEventType().get()); 134 | 135 | Map clientPayload = getClientPayload().getOrNull(); 136 | if (clientPayload != null && !clientPayload.isEmpty()) { 137 | repositoryDispatch.put("client_payload", clientPayload); 138 | } 139 | 140 | return new ObjectMapper().writeValueAsBytes(repositoryDispatch); 141 | } 142 | 143 | private int getStatusCode(HttpURLConnection connection) { 144 | try { 145 | return connection.getResponseCode(); 146 | } catch (IOException e) { 147 | getLogger() 148 | .warn("Failed to read the repository dispatch status code: " + e.getMessage()); 149 | } 150 | return NO_STATUS_CODE; 151 | } 152 | 153 | private String readResponse(HttpURLConnection connection) { 154 | try { 155 | return IOUtils.toString(connection.getErrorStream(), StandardCharsets.UTF_8); 156 | } catch (IOException e) { 157 | getLogger().warn("Failed to read the repository dispatch response: " + e.getMessage()); 158 | } 159 | return null; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/TaskException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2020 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | /** An exception that occurred while running a task. */ 23 | public class TaskException extends RuntimeException { 24 | 25 | private static final long serialVersionUID = 1L; 26 | 27 | public TaskException(String message) { 28 | super(message); 29 | } 30 | 31 | public TaskException(String message, Throwable cause) { 32 | super(message, cause); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/TaskUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.net.URI; 25 | import java.net.URL; 26 | import java.nio.charset.StandardCharsets; 27 | import java.nio.file.Files; 28 | import java.nio.file.Path; 29 | import java.util.Set; 30 | import java.util.stream.Collectors; 31 | import org.apache.commons.codec.digest.DigestUtils; 32 | import org.gradle.api.Task; 33 | import org.gradle.api.file.RegularFileProperty; 34 | 35 | final class TaskUtils { 36 | 37 | private static final String COMMENT_LINE = "#"; 38 | 39 | private TaskUtils() {} 40 | 41 | private static final String HTTPS_SCHEME = "HTTPS"; 42 | private static final String ADD_ON_EXTENSION = ".zap"; 43 | 44 | static Path downloadAddOn(Task task, String urlString) throws Exception { 45 | return downloadAddOn(task, urlString, task.getTemporaryDir().toPath()); 46 | } 47 | 48 | static Path downloadAddOn(Task task, String urlString, Path outputDir) throws Exception { 49 | return downloadFile(task, urlString, outputDir.resolve(extractFileName(urlString))); 50 | } 51 | 52 | static Path downloadFile(Task task, String urlString, Path outputFile) throws Exception { 53 | URL url = new URI(urlString).toURL(); 54 | if (!HTTPS_SCHEME.equalsIgnoreCase(url.getProtocol())) { 55 | throw new IllegalArgumentException( 56 | "The provided URL does not use HTTPS scheme: " + url.getProtocol()); 57 | } 58 | 59 | if (Files.exists(outputFile)) { 60 | task.getLogger().info("File already exists at specified path, skipping download."); 61 | return outputFile; 62 | } 63 | 64 | try (InputStream in = url.openStream()) { 65 | Files.copy(in, outputFile); 66 | } catch (IOException e) { 67 | throw new IOException("Failed to download the file: " + e.getMessage(), e); 68 | } 69 | task.getLogger().info("File downloaded to: " + outputFile); 70 | return outputFile; 71 | } 72 | 73 | private static String extractFileName(String url) { 74 | int idx = url.lastIndexOf("/"); 75 | if (idx == -1) { 76 | throw new IllegalArgumentException( 77 | "The provided URL does not have a file name: " + url); 78 | } 79 | String fileName = url.substring(idx + 1); 80 | if (!fileName.endsWith(ADD_ON_EXTENSION)) { 81 | throw new IllegalArgumentException( 82 | "The provided URL does not have a file with zap extension: " + fileName); 83 | } 84 | return fileName; 85 | } 86 | 87 | static String calculateChecksum(Path file, String checksumAlgorithm, String expectedChecksum) 88 | throws IOException { 89 | String checksum = new DigestUtils(checksumAlgorithm).digestAsHex(file.toFile()); 90 | if (expectedChecksum == null 91 | || expectedChecksum.isEmpty() 92 | || checksum.equals(expectedChecksum)) { 93 | return checksum; 94 | } 95 | 96 | throw new IllegalArgumentException( 97 | String.format( 98 | "Checksums do not match for: %s\nExpected:\n%s\nActual:\n%s", 99 | file, expectedChecksum, checksum)); 100 | } 101 | 102 | static Set readAllowedAddOns(RegularFileProperty fileProperty) throws IOException { 103 | Path file = fileProperty.getAsFile().get().toPath(); 104 | return Files.readAllLines(file, StandardCharsets.UTF_8).stream() 105 | .filter(s -> !s.startsWith(COMMENT_LINE) || !s.isEmpty()) 106 | .collect(Collectors.toSet()); 107 | } 108 | 109 | static boolean hasSecureScheme(URL url) { 110 | if (url == null) { 111 | return false; 112 | } 113 | return HTTPS_SCHEME.equalsIgnoreCase(url.getProtocol()); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/UpdateAddOnZapVersionsEntries.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2019 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.IOException; 23 | import java.net.URI; 24 | import java.net.URL; 25 | import java.nio.file.Files; 26 | import java.nio.file.Path; 27 | import java.time.LocalDate; 28 | import org.gradle.api.file.RegularFileProperty; 29 | import org.gradle.api.model.ObjectFactory; 30 | import org.gradle.api.provider.Property; 31 | import org.gradle.api.tasks.Input; 32 | import org.gradle.api.tasks.InputFile; 33 | import org.gradle.api.tasks.Optional; 34 | import org.gradle.api.tasks.TaskAction; 35 | import org.gradle.api.tasks.options.Option; 36 | 37 | /** A task that updates {@code ZapVersions.xml} files with an add-on. */ 38 | public abstract class UpdateAddOnZapVersionsEntries extends AbstractUpdateZapVersionsEntries 39 | implements AddOnZapVersionsUpdater { 40 | 41 | private final Property fromUrl; 42 | private final Property downloadUrl; 43 | private final Property releaseDate; 44 | 45 | public UpdateAddOnZapVersionsEntries() { 46 | ObjectFactory objects = getProject().getObjects(); 47 | this.fromUrl = objects.property(String.class); 48 | this.downloadUrl = objects.property(String.class); 49 | this.downloadUrl.set(fromUrl); 50 | this.releaseDate = objects.property(LocalDate.class); 51 | this.releaseDate.set(LocalDate.now()); 52 | 53 | setDescription("Updates ZapVersions.xml files with an add-on."); 54 | } 55 | 56 | @Option(option = "file", description = "The file system path to the add-on.") 57 | public void setFile(String path) { 58 | getFromFile().set(getProject().file(path)); 59 | } 60 | 61 | @InputFile 62 | @Optional 63 | public abstract RegularFileProperty getFromFile(); 64 | 65 | @Option(option = "url", description = "The URL to the add-on.") 66 | public void setUrl(String url) { 67 | fromUrl.set(url); 68 | } 69 | 70 | @Input 71 | @Optional 72 | public Property getFromUrl() { 73 | return fromUrl; 74 | } 75 | 76 | @Option(option = "downloadUrl", description = "The URL from where the add-on is downloaded.") 77 | public void setDownloadUrl(String url) { 78 | downloadUrl.set(url); 79 | } 80 | 81 | @Input 82 | @Optional 83 | public Property getDownloadUrl() { 84 | return downloadUrl; 85 | } 86 | 87 | @Option(option = "releaseDate", description = "The release date.") 88 | public void setReleaseDate(String date) { 89 | releaseDate.set(LocalDate.parse(date)); 90 | } 91 | 92 | @Input 93 | public Property getReleaseDate() { 94 | return releaseDate; 95 | } 96 | 97 | @TaskAction 98 | public void update() throws Exception { 99 | if (getFromFile().isPresent()) { 100 | if (fromUrl.isPresent()) { 101 | throw new IllegalArgumentException( 102 | "Only one of the properties, URL or file, can be set at the same time."); 103 | } 104 | 105 | if (!downloadUrl.isPresent()) { 106 | throw new IllegalArgumentException( 107 | "The download URL must be provided when specifying the file."); 108 | } 109 | } else if (!fromUrl.isPresent()) { 110 | throw new IllegalArgumentException( 111 | "Either one of the properties, URL or file, must be set."); 112 | } 113 | 114 | if (downloadUrl.get().isEmpty()) { 115 | throw new IllegalArgumentException("The download URL must not be empty."); 116 | } 117 | 118 | try { 119 | URL url = new URI(downloadUrl.get()).toURL(); 120 | if (!TaskUtils.hasSecureScheme(url)) { 121 | throw new IllegalArgumentException( 122 | "The provided download URL does not use HTTPS scheme: " 123 | + url.getProtocol()); 124 | } 125 | } catch (Exception e) { 126 | throw new IllegalArgumentException( 127 | "Failed to parse the download URL: " + e.getMessage(), e); 128 | } 129 | 130 | updateAddOn(getAddOn(), getDownloadUrl().get(), getReleaseDate().get()); 131 | } 132 | 133 | private Path getAddOn() throws Exception { 134 | if (getFromFile().isPresent()) { 135 | Path addOn = getFromFile().getAsFile().get().toPath(); 136 | if (!Files.isRegularFile(addOn)) { 137 | throw new IllegalArgumentException( 138 | "The provided path does not exist or it's not a file: " + addOn); 139 | } 140 | return addOn; 141 | } 142 | 143 | return TaskUtils.downloadAddOn(this, fromUrl.get()); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/UpdateAndCreatePullRequestAddOnRelease.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.nio.file.Path; 23 | import java.time.LocalDate; 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | import org.gradle.api.provider.Property; 27 | import org.gradle.api.tasks.Input; 28 | import org.gradle.api.tasks.options.Option; 29 | 30 | public abstract class UpdateAndCreatePullRequestAddOnRelease extends CreatePullRequest 31 | implements AddOnZapVersionsUpdater { 32 | 33 | private final Property envVar; 34 | private StringBuilder commitDescription; 35 | 36 | public UpdateAndCreatePullRequestAddOnRelease() { 37 | this.envVar = getProject().getObjects().property(String.class); 38 | this.commitDescription = new StringBuilder(); 39 | 40 | getCommitSummary().set("Release add-on(s)"); 41 | getCommitDescription().set(getProject().provider(commitDescription::toString)); 42 | 43 | setDescription( 44 | "Updates ZapVersions and creates a pull request to release an add-on (or several)."); 45 | } 46 | 47 | @Option( 48 | option = "envVar", 49 | description = "The name of the env var that has the add-on release data.") 50 | public void setEnvVar(String name) { 51 | getEnvVar().set(name); 52 | } 53 | 54 | @Input 55 | public Property getEnvVar() { 56 | return envVar; 57 | } 58 | 59 | @Override 60 | public void pullRequest() throws Exception { 61 | commitDescription.append("Release the following add-ons:"); 62 | 63 | List releasedAddOns = new ArrayList<>(); 64 | String data = System.getenv(getEnvVar().get()); 65 | for (AddOnReleaseData.Release release : AddOnReleaseData.read(data).getAddOns()) { 66 | String downloadUrl = release.getUrl(); 67 | 68 | Path addOn = TaskUtils.downloadAddOn(this, downloadUrl); 69 | calculateChecksum(addOn, release.getChecksum()); 70 | updateAddOn( 71 | addOn, 72 | downloadUrl, 73 | LocalDate.now(), 74 | addOnEntry -> 75 | releasedAddOns.add( 76 | "\n - " 77 | + addOnEntry.getName() 78 | + " version " 79 | + addOnEntry.getVersion())); 80 | } 81 | releasedAddOns.stream().sorted().forEach(commitDescription::append); 82 | 83 | super.pullRequest(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/UpdateFlathubData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2025 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.nio.charset.StandardCharsets; 26 | import java.nio.file.Files; 27 | import java.nio.file.Path; 28 | import java.nio.file.StandardCopyOption; 29 | import java.time.LocalDate; 30 | import java.util.Iterator; 31 | import java.util.Optional; 32 | import java.util.regex.Matcher; 33 | import java.util.regex.Pattern; 34 | import java.util.zip.ZipEntry; 35 | import java.util.zip.ZipFile; 36 | import org.apache.commons.configuration.XMLConfiguration; 37 | import org.gradle.api.file.RegularFileProperty; 38 | import org.gradle.api.tasks.InputFile; 39 | import org.gradle.api.DefaultTask; 40 | import org.gradle.api.provider.Property; 41 | import org.gradle.api.tasks.Input; 42 | import org.gradle.api.tasks.TaskAction; 43 | import org.zaproxy.gradle.ReleaseState.VersionChange; 44 | 45 | public abstract class UpdateFlathubData extends DefaultTask { 46 | 47 | @InputFile 48 | public abstract RegularFileProperty getReleaseState(); 49 | 50 | @InputFile 51 | public abstract RegularFileProperty getZapVersions(); 52 | 53 | @Input 54 | public abstract Property getBaseDirectory(); 55 | 56 | @TaskAction 57 | void executeTasks() throws Exception { 58 | ReleaseState releaseState = ReleaseState.read(getReleaseState().getAsFile().get()); 59 | if (!isNewMainRelease(releaseState)) { 60 | return; 61 | } 62 | 63 | XMLConfiguration zapVersionsXml = new CustomXmlConfiguration(); 64 | zapVersionsXml.load(getZapVersions().get().getAsFile()); 65 | 66 | String version = zapVersionsXml.getString("core.version"); 67 | String url = zapVersionsXml.getString("core.linux.url"); 68 | String hash = zapVersionsXml.getString("core.linux.hash").split(":", 2)[1]; 69 | 70 | Path repo = getBaseDirectory().get().toPath(); 71 | 72 | updateAppData(repo, version); 73 | updateJson(repo, url, hash); 74 | } 75 | 76 | private static boolean isNewMainRelease(ReleaseState releaseState) { 77 | VersionChange mainRelease = releaseState.getMainRelease(); 78 | return mainRelease != null && mainRelease.isNewVersion(); 79 | } 80 | 81 | private static void updateAppData(Path dir, String version) throws IOException { 82 | Path file = dir.resolve("org.zaproxy.ZAP.appdata.xml"); 83 | String contents = Files.readString(file); 84 | 85 | Matcher matcher = Pattern.compile("").matcher(contents); 86 | if (!matcher.find()) { 87 | throw new IOException("The XML entry release was not found in: " + file); 88 | } 89 | StringBuilder sb = new StringBuilder(); 90 | matcher.appendReplacement(sb, ""); 91 | matcher.appendTail(sb); 92 | 93 | Files.writeString(file, sb.toString()); 94 | } 95 | 96 | private static void updateJson(Path dir, String url, String hash) throws IOException { 97 | Path file = dir.resolve("org.zaproxy.ZAP.json"); 98 | String contents = Files.readString(file); 99 | 100 | Matcher matcher = Pattern.compile("url\": \"([^\\\"]+)\"").matcher(contents); 101 | if (!matcher.find()) { 102 | throw new IOException("The JSON url property was not found in: " + file); 103 | } 104 | StringBuilder sb = new StringBuilder(); 105 | matcher.appendReplacement(sb, "url\": \"" + url + "\""); 106 | matcher.appendTail(sb); 107 | 108 | matcher = Pattern.compile("sha256\": \"([^\\\"]+)\"").matcher(sb.toString()); 109 | if (!matcher.find()) { 110 | throw new IOException("The JSON sha256 property was not found in: " + file); 111 | } 112 | sb.setLength(0); 113 | matcher.appendReplacement(sb, "sha256\": \"" + hash + "\""); 114 | matcher.appendTail(sb); 115 | 116 | Files.writeString(file, sb.toString()); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/UpdateGettingStartedWebsitePage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2024 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.nio.charset.StandardCharsets; 26 | import java.nio.file.Files; 27 | import java.nio.file.Path; 28 | import java.nio.file.StandardCopyOption; 29 | import java.util.Iterator; 30 | import java.util.Optional; 31 | import java.util.regex.Matcher; 32 | import java.util.regex.Pattern; 33 | import java.util.zip.ZipEntry; 34 | import java.util.zip.ZipFile; 35 | import org.gradle.api.DefaultTask; 36 | import org.gradle.api.provider.Property; 37 | import org.gradle.api.tasks.Input; 38 | import org.gradle.api.tasks.TaskAction; 39 | 40 | public abstract class UpdateGettingStartedWebsitePage extends DefaultTask { 41 | 42 | @Input 43 | public abstract Property> getAddOn(); 44 | 45 | @Input 46 | public abstract Property getFilenameRegex(); 47 | 48 | @Input 49 | public abstract Property getGettingStartedPage(); 50 | 51 | @Input 52 | public abstract Property getPdfDirectory(); 53 | 54 | @TaskAction 55 | void executeTasks() throws Exception { 56 | Optional optionalAddOn = getAddOn().get(); 57 | if (optionalAddOn.isEmpty()) { 58 | return; 59 | } 60 | 61 | File addOn = optionalAddOn.get(); 62 | Pattern filenamePattern = Pattern.compile(getFilenameRegex().get()); 63 | String filename = null; 64 | 65 | try (ZipFile zip = new ZipFile(addOn)) { 66 | boolean found = false; 67 | for (Iterator it = zip.entries().asIterator(); 68 | it.hasNext() && !found; ) { 69 | ZipEntry entry = it.next(); 70 | if (!filenamePattern.matcher(entry.getName()).find()) { 71 | continue; 72 | } 73 | 74 | found = true; 75 | filename = extractFilename(entry.getName()); 76 | try (InputStream zis = zip.getInputStream(entry)) { 77 | Path target = getPdfDirectory().get().toPath().resolve(filename); 78 | Files.copy(zis, target, StandardCopyOption.REPLACE_EXISTING); 79 | } 80 | } 81 | } 82 | 83 | if (filename == null) { 84 | throw new IOException( 85 | "No file matching the provided filename pattern was found in the add-on."); 86 | } 87 | 88 | updateFilename(filename, filenamePattern, getGettingStartedPage().get().toPath()); 89 | } 90 | 91 | private static String extractFilename(String path) { 92 | return path.substring(path.indexOf('/') + 1); 93 | } 94 | 95 | private static void updateFilename(String filename, Pattern filenamePattern, Path file) 96 | throws IOException { 97 | String contents = new String(Files.readAllBytes(file), StandardCharsets.UTF_8); 98 | Matcher matcher = filenamePattern.matcher(contents); 99 | if (!matcher.find()) { 100 | throw new IOException("The filename pattern was not found in: " + file); 101 | } 102 | StringBuilder sb = new StringBuilder(); 103 | matcher.appendReplacement(sb, filename); 104 | matcher.appendTail(sb); 105 | Files.write(file, sb.toString().getBytes(StandardCharsets.UTF_8)); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/UpdateZapVersionWebsiteData.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.File; 23 | import java.nio.charset.StandardCharsets; 24 | import java.nio.file.Files; 25 | import java.nio.file.Path; 26 | import javax.inject.Inject; 27 | import org.gradle.api.DefaultTask; 28 | import org.gradle.api.file.ConfigurableFileCollection; 29 | import org.gradle.api.file.RegularFileProperty; 30 | import org.gradle.api.provider.Property; 31 | import org.gradle.api.tasks.InputFile; 32 | import org.gradle.api.tasks.InputFiles; 33 | import org.gradle.api.tasks.TaskAction; 34 | import org.gradle.workers.WorkAction; 35 | import org.gradle.workers.WorkParameters; 36 | import org.gradle.workers.WorkQueue; 37 | import org.gradle.workers.WorkerExecutor; 38 | import org.zaproxy.gradle.ReleaseState.VersionChange; 39 | 40 | /** Task that updates the ZAP version in files. */ 41 | public abstract class UpdateZapVersionWebsiteData extends DefaultTask { 42 | 43 | @InputFile 44 | public abstract RegularFileProperty getReleaseState(); 45 | 46 | @InputFiles 47 | public abstract ConfigurableFileCollection getDataFiles(); 48 | 49 | @Inject 50 | public abstract WorkerExecutor getWorkerExecutor(); 51 | 52 | @TaskAction 53 | public void update() { 54 | ReleaseState releaseState = ReleaseState.read(getReleaseState().getAsFile().get()); 55 | if (!isNewMainRelease(releaseState)) { 56 | return; 57 | } 58 | 59 | VersionChange mainRelease = releaseState.getMainRelease(); 60 | String previousVersion = mainRelease.getPreviousVersion(); 61 | String currentVersion = mainRelease.getCurrentVersion(); 62 | 63 | String previousVersionNoPatch = removePatchVersion(previousVersion); 64 | String currentVersionNoPatch = removePatchVersion(currentVersion); 65 | 66 | WorkQueue workQueue = getWorkerExecutor().noIsolation(); 67 | 68 | for (File file : getDataFiles()) { 69 | workQueue.submit( 70 | ReplaceVersions.class, 71 | parameters -> { 72 | parameters.getFile().set(file); 73 | 74 | parameters.getPreviousVersion().set(previousVersion); 75 | parameters.getCurrentVersion().set(currentVersion); 76 | 77 | parameters.getPreviousVersionNoPatch().set(previousVersionNoPatch); 78 | parameters.getCurrentVersionNoPatch().set(currentVersionNoPatch); 79 | }); 80 | } 81 | } 82 | 83 | private static boolean isNewMainRelease(ReleaseState releaseState) { 84 | VersionChange mainRelease = releaseState.getMainRelease(); 85 | return mainRelease != null && mainRelease.isNewVersion(); 86 | } 87 | 88 | public interface ReplaceVersionsParameters extends WorkParameters { 89 | 90 | RegularFileProperty getFile(); 91 | 92 | Property getPreviousVersion(); 93 | 94 | Property getCurrentVersion(); 95 | 96 | Property getPreviousVersionNoPatch(); 97 | 98 | Property getCurrentVersionNoPatch(); 99 | } 100 | 101 | public abstract static class ReplaceVersions implements WorkAction { 102 | 103 | @Override 104 | public void execute() { 105 | try { 106 | Path file = getParameters().getFile().getAsFile().get().toPath(); 107 | String contents = new String(Files.readAllBytes(file), StandardCharsets.UTF_8); 108 | Files.write( 109 | file, 110 | contents.replace( 111 | getParameters().getPreviousVersion().get(), 112 | getParameters().getCurrentVersion().get()) 113 | .replace( 114 | getParameters().getPreviousVersionNoPatch().get(), 115 | getParameters().getCurrentVersionNoPatch().get()) 116 | .getBytes(StandardCharsets.UTF_8)); 117 | } catch (Exception e) { 118 | throw new RuntimeException(e); 119 | } 120 | } 121 | } 122 | 123 | private static String removePatchVersion(String version) { 124 | int idx = version.lastIndexOf('.'); 125 | if (idx == -1) { 126 | return version; 127 | } 128 | return version.substring(0, idx); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/UpdateZapVersionsEntries.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | import java.nio.file.Files; 25 | import java.nio.file.Path; 26 | import java.util.function.Consumer; 27 | import org.apache.commons.configuration.XMLConfiguration; 28 | import org.gradle.api.file.ConfigurableFileCollection; 29 | import org.gradle.api.provider.Property; 30 | import org.gradle.api.tasks.Input; 31 | import org.gradle.api.tasks.InputFiles; 32 | 33 | interface UpdateZapVersionsEntries { 34 | 35 | @InputFiles 36 | ConfigurableFileCollection getInto(); 37 | 38 | @Input 39 | Property getChecksumAlgorithm(); 40 | 41 | default void updateZapVersionsFiles(Consumer consumer) throws Exception { 42 | if (getChecksumAlgorithm().get().isEmpty()) { 43 | throw new IllegalArgumentException("The checksum algorithm must not be empty."); 44 | } 45 | 46 | for (File zapVersionsFile : getInto()) { 47 | if (!Files.isRegularFile(zapVersionsFile.toPath())) { 48 | throw new IllegalArgumentException( 49 | "The provided path is not a file: " + zapVersionsFile); 50 | } 51 | 52 | XMLConfiguration zapVersionsXml = new CustomXmlConfiguration(); 53 | zapVersionsXml.load(zapVersionsFile); 54 | consumer.accept(zapVersionsXml); 55 | zapVersionsXml.save(zapVersionsFile); 56 | } 57 | } 58 | 59 | default String createChecksumString(Path file) throws IOException { 60 | return createChecksumString(file, null); 61 | } 62 | 63 | default String createChecksumString(Path file, String expectedChecksum) throws IOException { 64 | return getChecksumAlgorithm().get() + ":" + calculateChecksum(file, expectedChecksum); 65 | } 66 | 67 | default String calculateChecksum(Path file, String expectedChecksum) throws IOException { 68 | return TaskUtils.calculateChecksum(file, getChecksumAlgorithm().get(), expectedChecksum); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/crowdin/BuildEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.crowdin; 21 | 22 | import java.util.List; 23 | 24 | public class BuildEntry { 25 | 26 | private String repo; 27 | private List tasks; 28 | 29 | public String getRepo() { 30 | return repo; 31 | } 32 | 33 | public List getTasks() { 34 | return tasks; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/crowdin/BuildTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.crowdin; 21 | 22 | import java.util.List; 23 | 24 | public class BuildTask { 25 | 26 | private String name; 27 | private List args; 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public List getArgs() { 34 | return args; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/crowdin/DeployCrowdinTranslations.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.crowdin; 21 | 22 | import com.fasterxml.jackson.core.type.TypeReference; 23 | import com.fasterxml.jackson.databind.ObjectMapper; 24 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 25 | import java.io.File; 26 | import java.io.IOException; 27 | import java.nio.file.Path; 28 | import java.util.ArrayList; 29 | import java.util.List; 30 | import javax.inject.Inject; 31 | import org.apache.tools.ant.taskdefs.condition.Os; 32 | import org.eclipse.jgit.api.Git; 33 | import org.gradle.api.DefaultTask; 34 | import org.gradle.api.file.DirectoryProperty; 35 | import org.gradle.api.file.RegularFileProperty; 36 | import org.gradle.api.provider.Property; 37 | import org.gradle.api.tasks.Input; 38 | import org.gradle.api.tasks.InputDirectory; 39 | import org.gradle.api.tasks.InputFile; 40 | import org.gradle.api.tasks.Internal; 41 | import org.gradle.api.tasks.TaskAction; 42 | import org.gradle.process.ExecOperations; 43 | import org.zaproxy.gradle.CreatePullRequestImpl; 44 | import org.zaproxy.gradle.GitHubRepo; 45 | import org.zaproxy.gradle.GitHubUser; 46 | 47 | /** A task to deploy the resulting Crowdin translations into Git repositories. */ 48 | public abstract class DeployCrowdinTranslations extends DefaultTask { 49 | 50 | private static final String PACKAGES_DIR_TOKEN = "%packages_dir%"; 51 | private static final String OWNER = "zaproxy"; 52 | 53 | public DeployCrowdinTranslations() { 54 | DirectoryProperty buildDirectory = getProject().getLayout().getBuildDirectory(); 55 | getTranslationsPackageDirectory() 56 | .convention(buildDirectory.dir("crowdinTranslationPackages")); 57 | getRepositoriesDirectory() 58 | .convention(buildDirectory.dir("deployCrowdinTranslationsRepos").get().getAsFile()); 59 | getBaseBranchName().convention("main"); 60 | } 61 | 62 | @Inject 63 | protected ExecOperations getExecOperations() { 64 | throw new UnsupportedOperationException(); 65 | } 66 | 67 | @InputFile 68 | public abstract RegularFileProperty getDeployConfiguration(); 69 | 70 | @InputDirectory 71 | public abstract DirectoryProperty getTranslationsPackageDirectory(); 72 | 73 | @Input 74 | public abstract Property getRepositoriesDirectory(); 75 | 76 | @Internal 77 | public abstract Property getBaseBranchName(); 78 | 79 | @Internal 80 | public abstract Property getBranchName(); 81 | 82 | @Internal 83 | public abstract Property getUser(); 84 | 85 | @Internal 86 | public abstract Property getCommitSummary(); 87 | 88 | @Internal 89 | public abstract Property getCommitDescription(); 90 | 91 | @TaskAction 92 | void executeTasks() throws Exception { 93 | Path reposDir = getRepositoriesDirectory().get().toPath(); 94 | String packagesDir = 95 | getTranslationsPackageDirectory() 96 | .get() 97 | .getAsFile() 98 | .toPath() 99 | .toAbsolutePath() 100 | .toString(); 101 | 102 | for (BuildEntry buildEntry : readBuildEntries()) { 103 | Path repoDir = reposDir.resolve(buildEntry.getRepo()); 104 | GitHubRepo ghRepo = new GitHubRepo(OWNER, buildEntry.getRepo(), repoDir.toFile()); 105 | 106 | getProject().mkdir(repoDir); 107 | String cloneUrl = 108 | CreatePullRequestImpl.GITHUB_BASE_URL 109 | + ghRepo.getOwner() 110 | + "/" 111 | + ghRepo.getName() 112 | + ".git"; 113 | Git.cloneRepository().setURI(cloneUrl).setDirectory(repoDir.toFile()).call(); 114 | 115 | runTasks(repoDir, buildEntry.getTasks(), packagesDir); 116 | 117 | CreatePullRequestImpl.create( 118 | ghRepo, 119 | getUser().get(), 120 | getBranchName().get(), 121 | getBaseBranchName().get(), 122 | getCommitSummary().get(), 123 | getCommitDescription().get()); 124 | } 125 | } 126 | 127 | private void runTasks(Path repoDir, List tasks, String packagesDir) { 128 | for (BuildTask task : tasks) { 129 | List execArgs = new ArrayList<>(2); 130 | execArgs.add(task.getName()); 131 | if (task.getArgs() != null && !task.getArgs().isEmpty()) { 132 | task.getArgs().replaceAll(arg -> replacePackagesDirToken(arg, packagesDir)); 133 | execArgs.addAll(task.getArgs()); 134 | } 135 | runGradle(repoDir, execArgs); 136 | } 137 | } 138 | 139 | private static String replacePackagesDirToken(String arg, String packagesDir) { 140 | return arg.replace(PACKAGES_DIR_TOKEN, packagesDir); 141 | } 142 | 143 | private void runGradle(Path repoDir, List args) { 144 | List execArgs = new ArrayList<>(); 145 | execArgs.add("-Dorg.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m"); 146 | execArgs.add("-q"); 147 | execArgs.addAll(args); 148 | getExecOperations() 149 | .exec( 150 | spec -> { 151 | spec.environment(System.getenv()); 152 | spec.setWorkingDir(repoDir); 153 | spec.setExecutable(gradleWrapper()); 154 | spec.args(execArgs); 155 | }) 156 | .assertNormalExitValue(); 157 | } 158 | 159 | private List readBuildEntries() throws IOException { 160 | File file = getDeployConfiguration().get().getAsFile(); 161 | return new ObjectMapper(new YAMLFactory()) 162 | .readValue(file, new TypeReference>() {}); 163 | } 164 | 165 | private static String gradleWrapper() { 166 | if (Os.isFamily(Os.FAMILY_UNIX)) { 167 | return "./gradlew"; 168 | } 169 | return "gradlew.bat"; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/website/HelpSetFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.website; 21 | 22 | import java.io.IOException; 23 | import java.net.MalformedURLException; 24 | import java.net.URL; 25 | import java.net.URLClassLoader; 26 | import java.util.Locale; 27 | import java.util.function.Function; 28 | import javax.help.HelpSet; 29 | import javax.help.HelpSetException; 30 | import org.zaproxy.zap.control.AddOn; 31 | import org.zaproxy.zap.extension.help.ExtensionHelp; 32 | import org.zaproxy.zap.utils.LocaleUtils; 33 | 34 | /** 35 | * Factory of {@link HelpSet}, created from an add-on (if present). 36 | * 37 | *

First checks if the add-on declares the {@code HelpSet}, otherwise it searches in the default 38 | * locations. 39 | */ 40 | final class HelpSetFactory { 41 | 42 | private HelpSetFactory() {} 43 | 44 | /** 45 | * Creates the {@code HelpSet} for the given add-on. 46 | * 47 | * @param addOn the add-on that might contain the {@code HelpSet}. 48 | * @param helpAddOn {@code true} if the given add-on has the core help, {@code false} otherwise. 49 | * @return the {@code HelpSet} or {@code null} if not found. 50 | * @throws WebsitePageGenerationException if an error occurred while searching or creating the 51 | * {@code HelpSet}. 52 | */ 53 | static HelpSet createHelpSet(AddOn addOn, boolean helpAddOn) { 54 | try (URLClassLoader classLoader = 55 | new URLClassLoader( 56 | new URL[] {addOn.getFile().toURI().toURL()}, 57 | HelpSetFactory.class.getClassLoader())) { 58 | if (helpAddOn) { 59 | return createHelpSet(classLoader, ExtensionHelp.HELP_SET_FILE_NAME, ""); 60 | } 61 | 62 | AddOn.HelpSetData helpSetData = addOn.getHelpSetData(); 63 | if (!helpSetData.isEmpty()) { 64 | return createHelpSet( 65 | classLoader, helpSetData.getBaseName(), helpSetData.getLocaleToken()); 66 | } 67 | 68 | for (String extension : addOn.getExtensions()) { 69 | URL url = getHelpSetUrl(classLoader, extension); 70 | if (url != null) { 71 | return createHelpSet(classLoader, url); 72 | } 73 | } 74 | return null; 75 | } catch (MalformedURLException e) { 76 | throw new WebsitePageGenerationException("Failed to convert the file path to URL:", e); 77 | } catch (IOException e) { 78 | throw new WebsitePageGenerationException( 79 | "Failed to read the contents of the add-on:", e); 80 | } 81 | } 82 | 83 | private static HelpSet createHelpSet( 84 | ClassLoader classLoader, String baseName, String localeToken) { 85 | URL helpSetUrl = findHelpSet(baseName, localeToken, classLoader::getResource); 86 | 87 | if (helpSetUrl == null) { 88 | throw new WebsitePageGenerationException( 89 | "Declared HelpSet not found in the add-on, with base name: " 90 | + baseName 91 | + (localeToken.isEmpty() ? "" : " and locale token: " + localeToken)); 92 | } 93 | return createHelpSet(classLoader, helpSetUrl); 94 | } 95 | 96 | private static URL findHelpSet( 97 | String baseName, String localeToken, Function function) { 98 | return LocaleUtils.findResource( 99 | baseName, 100 | ExtensionHelp.HELP_SET_FILE_EXTENSION, 101 | localeToken, 102 | Locale.ROOT, 103 | function); 104 | } 105 | 106 | private static HelpSet createHelpSet(ClassLoader classLoader, URL helpSetUrl) { 107 | try { 108 | return new HelpSet(classLoader, helpSetUrl); 109 | } catch (HelpSetException e) { 110 | throw new WebsitePageGenerationException( 111 | "An error occured while loading the HelpSet from the add-on.", e); 112 | } 113 | } 114 | 115 | private static URL getHelpSetUrl(ClassLoader classLoader, String extension) { 116 | String extensionPackage = extension.substring(0, extension.lastIndexOf('.')); 117 | String localeToken = "%LC%"; 118 | Function getResource = classLoader::getResource; 119 | URL helpSetUrl = 120 | findHelpSet( 121 | extensionPackage 122 | + ".resources.help" 123 | + localeToken 124 | + "." 125 | + ExtensionHelp.HELP_SET_FILE_NAME, 126 | localeToken, 127 | getResource); 128 | if (helpSetUrl == null) { 129 | // Search in old location 130 | helpSetUrl = 131 | findHelpSet( 132 | extensionPackage 133 | + ".resource.help" 134 | + localeToken 135 | + "." 136 | + ExtensionHelp.HELP_SET_FILE_NAME, 137 | localeToken, 138 | getResource); 139 | } 140 | return helpSetUrl; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/website/SourceImage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.website; 21 | 22 | import java.net.URL; 23 | 24 | /** An image contained in the add-on. */ 25 | class SourceImage { 26 | 27 | private final String src; 28 | private final URL url; 29 | 30 | SourceImage(String src, URL url) { 31 | this.src = src; 32 | this.url = url; 33 | } 34 | 35 | URL getUrl() { 36 | return url; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return src; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/website/SourcePage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.website; 21 | 22 | import java.net.URL; 23 | import java.util.Objects; 24 | import org.jsoup.nodes.Document; 25 | 26 | /** A source page (HTML) contained in the add-on. */ 27 | class SourcePage { 28 | 29 | private final PageFrontMatter frontMatter; 30 | private final URL path; 31 | private final String relativePath; 32 | private final String sitePath; 33 | private final String siteUrl; 34 | private final Document document; 35 | private final boolean section; 36 | 37 | SourcePage(PageFrontMatter frontMatter, String sitePath) { 38 | this.frontMatter = frontMatter; 39 | this.path = null; 40 | this.relativePath = null; 41 | this.sitePath = sitePath; 42 | this.siteUrl = null; 43 | this.document = null; 44 | this.section = false; 45 | } 46 | 47 | SourcePage( 48 | PageFrontMatter frontMatter, 49 | URL path, 50 | String relativePath, 51 | String sitePath, 52 | String siteUrl, 53 | Document document, 54 | boolean section) { 55 | this.frontMatter = frontMatter; 56 | this.path = Objects.requireNonNull(path); 57 | this.relativePath = Objects.requireNonNull(relativePath); 58 | this.sitePath = Objects.requireNonNull(sitePath); 59 | this.siteUrl = Objects.requireNonNull(siteUrl); 60 | this.document = document; 61 | this.section = section; 62 | } 63 | 64 | PageFrontMatter getFrontMatter() { 65 | return frontMatter; 66 | } 67 | 68 | URL getPath() { 69 | return path; 70 | } 71 | 72 | String getRelativePath() { 73 | return relativePath; 74 | } 75 | 76 | String getSitePath() { 77 | return sitePath; 78 | } 79 | 80 | String getSiteUrl() { 81 | return siteUrl; 82 | } 83 | 84 | Document getDocument() { 85 | return document; 86 | } 87 | 88 | boolean isSection() { 89 | return section; 90 | } 91 | 92 | @Override 93 | public int hashCode() { 94 | return relativePath.hashCode(); 95 | } 96 | 97 | @Override 98 | public boolean equals(Object obj) { 99 | if (this == obj) { 100 | return true; 101 | } 102 | if (obj == null) { 103 | return false; 104 | } 105 | if (getClass() != obj.getClass()) { 106 | return false; 107 | } 108 | SourcePage other = (SourcePage) obj; 109 | return relativePath.equals(other.relativePath); 110 | } 111 | 112 | @Override 113 | public String toString() { 114 | return relativePath; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/website/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.website; 21 | 22 | import java.net.URI; 23 | import java.net.URL; 24 | import java.util.Locale; 25 | import java.util.regex.Pattern; 26 | import org.apache.commons.lang3.StringUtils; 27 | import org.zaproxy.gradle.website.TocTree.TocItem; 28 | 29 | /** Utility methods needed for website page generation. */ 30 | final class Utils { 31 | 32 | private static final String ABSOLUTE_SCHEME = "//"; 33 | private static final String HTTP_SCHEME = "http://"; 34 | private static final String HTTPS_SCHEME = "https://"; 35 | private static final String MAILTO_SCHEME = "mailto:"; 36 | private static final String WWW_SUBDOMAIN = "www."; 37 | 38 | private static final Pattern HTML_EXTENSION = 39 | Pattern.compile("\\.html$", Pattern.CASE_INSENSITIVE); 40 | 41 | private static final String MARKDOWN_EXTENSION = ".md"; 42 | 43 | private Utils() {} 44 | 45 | static String createContentsDirName(TocItem tocItem) { 46 | String url = tocItem.getTarget().toString(); 47 | int idx = url.lastIndexOf('/'); 48 | return url.substring(0, idx); 49 | } 50 | 51 | static String createAddOnDirName(TocItem addOnTocItem) { 52 | return addOnTocItem 53 | .getText() 54 | .toLowerCase(Locale.ROOT) 55 | .replaceAll("[ /:]", "-") 56 | .replaceAll("-{2,}", "-"); 57 | } 58 | 59 | static String createSiteFileName(String path, String newFileExtension) { 60 | StringBuilder strBuilderFileName = new StringBuilder(); 61 | String[] segments = path.split("/", -1); 62 | for (int i = 0; i < segments.length - 1; i++) { 63 | strBuilderFileName.append(StringUtils.capitalize(segments[i])); 64 | } 65 | String fileName = StringUtils.capitalize(segments[segments.length - 1]); 66 | strBuilderFileName.append(HTML_EXTENSION.matcher(fileName).replaceFirst(newFileExtension)); 67 | 68 | return strBuilderFileName.toString(); 69 | } 70 | 71 | static String createSitePath(String path) { 72 | return HTML_EXTENSION 73 | .matcher(path) 74 | .replaceFirst(MARKDOWN_EXTENSION) 75 | .toLowerCase(Locale.ROOT); 76 | } 77 | 78 | static String createSiteUrl(String path) { 79 | return HTML_EXTENSION.matcher(path).replaceFirst("/").toLowerCase(Locale.ROOT); 80 | } 81 | 82 | static String createRedirectPath(String urlPath, String childPath) { 83 | return urlPath 84 | + HTML_EXTENSION.matcher(childPath).replaceFirst("/").toLowerCase(Locale.ROOT); 85 | } 86 | 87 | static URL createUrlFor(URL file, String path) { 88 | try { 89 | var resolved = new URI(file.getPath()).resolve(path); 90 | return new URI(file.getProtocol(), resolved.toASCIIString(), null).toURL(); 91 | } catch (Exception e) { 92 | throw new WebsitePageGenerationException( 93 | "Failed to create the URL with " + file + " and " + path, e); 94 | } 95 | } 96 | 97 | static String normalisedPath(String baseDir, URL file, String path) { 98 | return normalisedPath(baseDir, createUrlFor(file, path)); 99 | } 100 | 101 | static String normalisedPath(String baseDir, URL url) { 102 | return normalisePath(baseDir, url.toString()); 103 | } 104 | 105 | private static String normalisePath(String baseDir, String path) { 106 | if (!startsWithDir(path, baseDir)) { 107 | throw new WebsitePageGenerationException( 108 | "Path " + path + " not under base dir " + baseDir); 109 | } 110 | return path.substring(baseDir.length() + 1); 111 | } 112 | 113 | static String normalisedImagePath(String baseDir, String imagesDirName, URL url) { 114 | String path = url.toString(); 115 | if (startsWithDir(path, baseDir)) { 116 | path = normalisePath(baseDir, path); 117 | if (path.startsWith(imagesDirName)) { 118 | path = path.substring(imagesDirName.length() + 1); 119 | } 120 | } else { 121 | path = path.substring(path.lastIndexOf('/') + 1); 122 | } 123 | return path; 124 | } 125 | 126 | private static boolean startsWithDir(String path, String dir) { 127 | return path.startsWith(normaliseFileSystemPath(dir)); 128 | } 129 | 130 | static String normaliseFileSystemPath(String path) { 131 | return path.replace('\\', '/'); 132 | } 133 | 134 | static boolean isExternalLink(String href) { 135 | return StringUtils.startsWithIgnoreCase(href, HTTP_SCHEME) 136 | || StringUtils.startsWithIgnoreCase(href, HTTPS_SCHEME) 137 | || StringUtils.startsWithIgnoreCase(href, ABSOLUTE_SCHEME) 138 | || StringUtils.startsWithIgnoreCase(href, MAILTO_SCHEME) 139 | || StringUtils.startsWithIgnoreCase(href, WWW_SUBDOMAIN); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/website/WebsitePageGenerationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2021 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.website; 21 | 22 | public class WebsitePageGenerationException extends RuntimeException { 23 | 24 | private static final long serialVersionUID = 1L; 25 | 26 | WebsitePageGenerationException() { 27 | super(); 28 | } 29 | 30 | WebsitePageGenerationException(String message) { 31 | super(message); 32 | } 33 | 34 | WebsitePageGenerationException(String message, Throwable cause) { 35 | super(message, cause); 36 | } 37 | 38 | WebsitePageGenerationException(Throwable cause) { 39 | super(cause); 40 | } 41 | 42 | protected WebsitePageGenerationException( 43 | String message, 44 | Throwable cause, 45 | boolean enableSuppression, 46 | boolean writableStackTrace) { 47 | super(message, cause, enableSuppression, writableStackTrace); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /buildSrc/src/main/java/org/zaproxy/gradle/website/WebsiteSbomPageGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2023 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.gradle.website; 21 | 22 | import com.fasterxml.jackson.databind.JsonNode; 23 | import com.fasterxml.jackson.databind.ObjectMapper; 24 | import com.fasterxml.jackson.databind.node.ArrayNode; 25 | import java.io.StringWriter; 26 | import java.nio.charset.StandardCharsets; 27 | import java.nio.file.Files; 28 | import java.nio.file.Path; 29 | import java.util.Set; 30 | import java.util.TreeSet; 31 | import java.util.stream.Collectors; 32 | import java.util.stream.StreamSupport; 33 | 34 | public class WebsiteSbomPageGenerator { 35 | 36 | private static final ObjectMapper MAPPER = new ObjectMapper(); 37 | private static final String NOTICE = 38 | "This page was automatically generated from the add-on's SBOM."; 39 | 40 | public static void generate( 41 | Path bomPath, 42 | String bomUrl, 43 | String pageTitle, 44 | String addOnId, 45 | String addOnVersion, 46 | Path outputFile) 47 | throws Exception { 48 | PageFrontMatter frontMatter = new PageFrontMatter("sbom", pageTitle, 1); 49 | JsonNode bomJson = MAPPER.readTree(bomPath.toFile()); 50 | Set resultComponents = new TreeSet<>(); 51 | var componentsJsonArray = (ArrayNode) bomJson.get("components"); 52 | for (JsonNode component : componentsJsonArray) { 53 | resultComponents.add( 54 | new PageFrontMatter.SbomDataComponent( 55 | component.get("name").asText(), 56 | component.get("version").asText(), 57 | createLicensesString(component))); 58 | } 59 | frontMatter.setSbomData( 60 | new PageFrontMatter.SbomData( 61 | bomJson.get("bomFormat").asText(), bomUrl, resultComponents)); 62 | frontMatter.setAddOnData(new PageFrontMatter.AddOnData(addOnId, addOnVersion)); 63 | var writer = new StringWriter(); 64 | frontMatter.writeTo(NOTICE, writer); 65 | Files.write(outputFile, writer.toString().getBytes(StandardCharsets.UTF_8)); 66 | } 67 | 68 | private static String createLicensesString(JsonNode component) { 69 | var licenses = (ArrayNode) component.get("licenses"); 70 | if (licenses == null) { 71 | return ""; 72 | } 73 | 74 | return StreamSupport.stream(licenses.spliterator(), false) 75 | .map(WebsiteSbomPageGenerator::licenseObjectToString) 76 | .filter(e -> e != null) 77 | .collect(Collectors.joining(", ")); 78 | } 79 | 80 | private static String licenseObjectToString(JsonNode l) { 81 | if (!l.has("license")) { 82 | return get(l, "expression"); 83 | } 84 | var license = l.get("license"); 85 | var id = get(license, "id"); 86 | if (id != null) { 87 | return id; 88 | } 89 | return get(license, "name"); 90 | } 91 | 92 | private static String get(JsonNode node, String property) { 93 | if (node.has(property)) { 94 | return node.get(property).asText(); 95 | } 96 | return null; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/org/zaproxy/gradle/GitHubRepo.kt: -------------------------------------------------------------------------------- 1 | package org.zaproxy.gradle 2 | 3 | import java.io.File 4 | 5 | data class GitHubRepo(val owner: String, val name: String, val dir: File) { 6 | 7 | override fun toString() = "$owner/$name" 8 | } 9 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/org/zaproxy/gradle/GitHubUser.kt: -------------------------------------------------------------------------------- 1 | package org.zaproxy.gradle 2 | 3 | data class GitHubUser(val name: String, val email: String, val authToken: String?) 4 | -------------------------------------------------------------------------------- /buildSrc/src/main/kotlin/org/zaproxy/gradle/ZapTask.kt: -------------------------------------------------------------------------------- 1 | import org.gradle.api.plugins.JavaPluginExtension 2 | import org.gradle.api.tasks.JavaExec 3 | import org.gradle.kotlin.dsl.get 4 | 5 | open class ZapTask : JavaExec() { 6 | 7 | init { 8 | group = "ZAP" 9 | classpath = project.configurations["runtimeClasspath"] + 10 | project.extensions.getByType(JavaPluginExtension::class.java).sourceSets["main"].output 11 | dependsOn("classes") 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /docs/headers/README.MD: -------------------------------------------------------------------------------- 1 | # Standard license headers to be used in zaproxy repos. 2 | 3 | Replace `$YEAR` with the current year. -------------------------------------------------------------------------------- /docs/headers/license.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright $YEAR The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ -------------------------------------------------------------------------------- /docs/headers/license.script: -------------------------------------------------------------------------------- 1 | # 2 | # Zed Attack Proxy (ZAP) and its related class files. 3 | # 4 | # ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | # 6 | # Copyright $YEAR The ZAP Development Team 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. -------------------------------------------------------------------------------- /docs/issue-templates/README.MD: -------------------------------------------------------------------------------- 1 | # Standard issue responses 2 | 3 | Standard issue responses to be used by the ZAP Core Team. 4 | 5 | For ease of use they can be manually added to https://github.com/settings/replies 6 | 7 | ### Question As Issue 8 | Please do not ask questions as issues. 9 | 10 | The ZAP User Group is the place to ask them: https://groups.google.com/g/zaproxy-users 11 | 12 | ### Non ZAP Issue 13 | This applies to a third party component that is not maintained by the ZAP Team. Please look for their preferred support mechanism. 14 | 15 | You can also try the [ZAP User Group](https://groups.google.com/g/zaproxy-users). 16 | 17 | ### Virus Report 18 | Thank you for letting us know. We will try to get in touch with the vendor, but this issue is being closed as it is really a problem with their detection and not our code. 19 | 20 | See https://www.zaproxy.org/faq/why-does-my-antivirus-tool-flag-zap/ 21 | 22 | ### Browser Not Found 23 | Please follow this FAQ: https://www.zaproxy.org/faq/no-browser/ 24 | 25 | You will see that the last line is: "If all fails then ask on the [ZAP User Group](https://groups.google.com/g/zaproxy-users), but make sure you mention you have checked this FAQ otherwise you will just be redirected back to here!" 26 | 27 | -------------------------------------------------------------------------------- /files/launch/2.6.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 |

ZAP 2.7.0 is available now!

6 | 7 | Use the ZAP "Help / Check for Updates..." menu option to download it.

8 | 9 | -------------------------------------------------------------------------------- /files/launch/2.7.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 |

ZAP 2.8.0 with the Heads Up Display is available now!

6 | 7 | Use the ZAP "Help / Check for Updates..." menu option to download it.

8 | -------------------------------------------------------------------------------- /files/launch/2.8.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 |

Explore your application with ZAP

6 | 7 | This browser is automatically configured to proxy via ZAP and to ignore certificate warnings.
8 | The more effectively you explore your application the better ZAP will understand and be able to attack it.

9 | 10 |

The ZAP HUD

11 | 12 | This version includes the ZAP Heads Up Display (HUD).
13 | The HUD is a brand new innovative interface that brings ZAP into the browser.
14 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 15 | see security information from ZAP and also allowing you to interact with it.
16 | The HUD includes a tutorial which will introduce you to all of the features it provides - 17 | you are strongly recommended to take it. 18 | 19 | 20 | 21 | 23 |

Sumisiyasat sa iyong aplikasyon sa ZAP

24 | 25 | Ang browser ay awtomatikong isinasaayos sa proxy sa pamamagitan ng ZAP ay huwag pansinin ang mga sertipiko na mga babala.
26 | 27 | Ang pinaka epektibong pagtuklas sa iyong aplikasyon ang mas mahusay na ZAP ay mauunawaan at pwede kang umatake nito.

28 | 29 |

The ZAP HUD

30 | 31 | This version includes the ZAP Heads Up Display (HUD).
32 | The HUD is a brand new innovative interface that brings ZAP into the browser.
33 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 34 | see security information from ZAP and also allowing you to interact with it.
35 | The HUD includes a tutorial which will introduce you to all of the features it provides - 36 | you are strongly recommended to take it. 37 | 38 | 39 | 40 | 42 |

Explorez votre application avec ZAP

43 | 44 | Ce navigateur est automatiquement configuré en proxy via ZAP et ignore les avertissements de certificat.
45 | 46 | Plus vous explorez efficacement votre application, mieux ZAP comprendrez il et pourrez l'attaquer.

47 | 48 |

The ZAP HUD

49 | 50 | This version includes the ZAP Heads Up Display (HUD).
51 | The HUD is a brand new innovative interface that brings ZAP into the browser.
52 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 53 | see security information from ZAP and also allowing you to interact with it.
54 | The HUD includes a tutorial which will introduce you to all of the features it provides - 55 | you are strongly recommended to take it. 56 | 57 | 58 | 59 | 61 |

Jelajahi aplikasi Anda dengan ZAP

62 | 63 | Peramban ini secara otomatis dikonfigurasi untuk menggunakan proxy melalui ZAP dan mengabaikan peringatan sertifikat.
64 | 65 | Lebih efektif Anda menjelajahi aplikasi, ZAP akan mengerti dan dapat menyerangnya dengan lebih baik.

66 | 67 |

The ZAP HUD

68 | 69 | This version includes the ZAP Heads Up Display (HUD).
70 | The HUD is a brand new innovative interface that brings ZAP into the browser.
71 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 72 | see security information from ZAP and also allowing you to interact with it.
73 | The HUD includes a tutorial which will introduce you to all of the features it provides - 74 | you are strongly recommended to take it. 75 | 76 | 77 | 78 | 80 |

Uygulamanızı ZAP ile keşfedin

81 | Bu tarayıcı ZAP üzerinden otomatik olarak vekil sunucu olarak ve sertifika uyarılarını göz ardı etmek için yapılandırılmıştır.
82 | Uygulamanızda ne kadar verimli dolaşırsanız, ZAP yapıyı o kadar iyi anlayacak ve etkin olarak saldırabilecektir.

83 | 84 |

The ZAP HUD

85 | 86 | This version includes the ZAP Heads Up Display (HUD).
87 | The HUD is a brand new innovative interface that brings ZAP into the browser.
88 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 89 | see security information from ZAP and also allowing you to interact with it.
90 | The HUD includes a tutorial which will introduce you to all of the features it provides - 91 | you are strongly recommended to take it. 92 | -------------------------------------------------------------------------------- /files/launch/README.md: -------------------------------------------------------------------------------- 1 | # Quick Start Launch Pages 2 | This directory contains files containing the HTML displayed by default when 3 | ZAP launches browsers via the Quick Start add-on. 4 | 5 | ## Locale support 6 | The files can support multiple locales. 7 | Each section must be separated via the string: 8 | ``` 9 | 10 | ``` 11 | 12 | The first line of the first section should be: 13 | ``` 14 | 15 | ``` 16 | 17 | The first line of following sections should contain the relevant locale: 18 | ``` 19 | 20 | ``` 21 | -------------------------------------------------------------------------------- /files/launch/dev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 |

Explore your application with ZAP

6 | 7 | This browser is automatically configured to proxy via ZAP and to ignore certificate warnings.
8 | The more effectively you explore your application the better ZAP will understand and be able to attack it.

9 | 10 |

The ZAP HUD

11 | 12 | This version includes the ZAP Heads Up Display (HUD).
13 | The HUD is a brand new innovative interface that brings ZAP into the browser.
14 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 15 | see security information from ZAP and also allowing you to interact with it.
16 | The HUD includes a tutorial which will introduce you to all of the features it provides - 17 | you are strongly recommended to take it. 18 | 19 | 20 | 21 | 23 |

Sumisiyasat sa iyong aplikasyon sa ZAP

24 | 25 | Ang browser ay awtomatikong isinasaayos sa proxy sa pamamagitan ng ZAP ay huwag pansinin ang mga sertipiko na mga babala.
26 | 27 | Ang pinaka epektibong pagtuklas sa iyong aplikasyon ang mas mahusay na ZAP ay mauunawaan at pwede kang umatake nito.

28 | 29 |

The ZAP HUD

30 | 31 | This version includes the ZAP Heads Up Display (HUD).
32 | The HUD is a brand new innovative interface that brings ZAP into the browser.
33 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 34 | see security information from ZAP and also allowing you to interact with it.
35 | The HUD includes a tutorial which will introduce you to all of the features it provides - 36 | you are strongly recommended to take it. 37 | 38 | 39 | 40 | 42 |

Explorez votre application avec ZAP

43 | 44 | Ce navigateur est automatiquement configuré en proxy via ZAP et ignore les avertissements de certificat.
45 | 46 | Plus vous explorez efficacement votre application, mieux ZAP comprendrez il et pourrez l'attaquer.

47 | 48 |

The ZAP HUD

49 | 50 | This version includes the ZAP Heads Up Display (HUD).
51 | The HUD is a brand new innovative interface that brings ZAP into the browser.
52 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 53 | see security information from ZAP and also allowing you to interact with it.
54 | The HUD includes a tutorial which will introduce you to all of the features it provides - 55 | you are strongly recommended to take it. 56 | 57 | 58 | 59 | 61 |

Jelajahi aplikasi Anda dengan ZAP

62 | 63 | Peramban ini secara otomatis dikonfigurasi untuk menggunakan proxy melalui ZAP dan mengabaikan peringatan sertifikat.
64 | 65 | Lebih efektif Anda menjelajahi aplikasi, ZAP akan mengerti dan dapat menyerangnya dengan lebih baik.

66 | 67 |

The ZAP HUD

68 | 69 | This version includes the ZAP Heads Up Display (HUD).
70 | The HUD is a brand new innovative interface that brings ZAP into the browser.
71 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 72 | see security information from ZAP and also allowing you to interact with it.
73 | The HUD includes a tutorial which will introduce you to all of the features it provides - 74 | you are strongly recommended to take it. 75 | 76 | 77 | 78 | 80 |

Uygulamanızı ZAP ile keşfedin

81 | Bu tarayıcı ZAP üzerinden otomatik olarak vekil sunucu olarak ve sertifika uyarılarını göz ardı etmek için yapılandırılmıştır.
82 | Uygulamanızda ne kadar verimli dolaşırsanız, ZAP yapıyı o kadar iyi anlayacak ve etkin olarak saldırabilecektir.

83 | 84 |

The ZAP HUD

85 | 86 | This version includes the ZAP Heads Up Display (HUD).
87 | The HUD is a brand new innovative interface that brings ZAP into the browser.
88 | When you navigate to a target site then the HUD will overlay information into your browser allowing you to 89 | see security information from ZAP and also allowing you to interact with it.
90 | The HUD includes a tutorial which will introduce you to all of the features it provides - 91 | you are strongly recommended to take it. 92 | -------------------------------------------------------------------------------- /files/news/2_10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 29 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/download/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/2_11.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 38 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/download/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/2_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 44 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/download/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/2_13.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 48 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/download/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/2_14.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/download/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/2_15.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 53 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/download/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/2_16.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 54 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/blog/2025-03-25-zap-2-16-1/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/2_8.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/download/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/2_9.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/download/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /files/news/dev.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 54 5 | 6 | ZAP 2.16.1 is available now 7 | https://www.zaproxy.org/blog/2025-03-25-zap-2-16-1/ 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /gradle/ci.gradle.kts: -------------------------------------------------------------------------------- 1 | // Build tweaks when running in GitHub CI 2 | 3 | fun isEnvVarTrue(envvar: String) = System.getenv(envvar) == "true" 4 | 5 | if (isEnvVarTrue("CI") && System.getenv("GITHUB_WORKFLOW") == "Java CI") { 6 | 7 | tasks.withType(Test::class).configureEach { 8 | testLogging { 9 | exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL 10 | } 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /gradle/crowdin.yml: -------------------------------------------------------------------------------- 1 | projects: 2 | - id: 9301 3 | - id: 32705 4 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zaproxy/zap-admin/ab815105beadb225f19c174024e0d08831b6f353/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionSha256Sum=fba8464465835e74f7270bbf43d6d8a8d7709ab0a43ce1aa3323f73e9aa0c612 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip 5 | networkTimeout=10000 6 | validateDistributionUrl=true 7 | zipStoreBase=GRADLE_USER_HOME 8 | zipStorePath=wrapper/dists 9 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /scripts/generate_events_page.js: -------------------------------------------------------------------------------- 1 | // This is a ZAP standalone script - it will only run in ZAP. 2 | // It generates the data for the events page at https://www.zaproxy.org/docs/internal-events/ 3 | // The pages were created after starting a ZAP weekly release with the '-addoninstallall' option. 4 | 5 | // Change the FILE below to match the local alerts data file 6 | var FILE = "/zap/wrk/zaproxy-website/site/data/events.yaml"; 7 | 8 | var FileWriter = Java.type('java.io.FileWriter'); 9 | var PrintWriter = Java.type('java.io.PrintWriter'); 10 | var ZAP = Java.type('org.zaproxy.zap.ZAP'); 11 | 12 | var fw = new FileWriter(FILE); 13 | var pw = new PrintWriter(fw); 14 | 15 | function isInExtensions(path) { 16 | return path.startsWith("org.zaproxy.addon") || 17 | (path.startsWith("org.zaproxy.zap.extension") 18 | && ! path.startsWith("org.zaproxy.zap.extension.alert") 19 | && ! path.startsWith("org.zaproxy.zap.extension.ascan") 20 | && ! path.startsWith("org.zaproxy.zap.extension.brk") 21 | && ! path.startsWith("org.zaproxy.zap.extension.spider")); 22 | } 23 | 24 | pw.println ("# The events raised in ZAP"); 25 | pw.println ("---"); 26 | 27 | var publishers = ZAP.eventBus.getPublisherNames().toArray(); 28 | for (var i=0; i < publishers.length; i++) { 29 | var events = ZAP.eventBus.getEventTypesForPublisher(publishers[i]).toArray(); 30 | for (var j=0; j < events.length; j++) { 31 | // Assume the core to start with 32 | var publisherJava = publishers[i].replaceAll("\\.", "\\/") + ".java"; 33 | var link = "https://github.com/zaproxy/zaproxy/blob/main/zap/src/main/java/" + publisherJava; 34 | if (isInExtensions(publishers[i])) { 35 | var pkg = publishers[i].split(".")[4]; 36 | if (publishers[i].startsWith("org.zaproxy.addon")) { 37 | pkg = publishers[i].split(".")[3]; 38 | } 39 | if (publishers[i].startsWith("org.zaproxy.zap.extension.hud")) { 40 | link = "https://github.com/zaproxy/zap-hud/tree/main/src/main/java/" + publisherJava; 41 | } else { 42 | link = "https://github.com/zaproxy/zap-extensions/blob/main/addOns/" + pkg + "/src/main/java/" + publisherJava; 43 | } 44 | } 45 | 46 | pw.println(); 47 | pw.println("- publisher: " + publishers[i]); 48 | pw.println(" link: " + link); 49 | pw.println(" event: " + events[j]); 50 | } 51 | } 52 | pw.close(); 53 | -------------------------------------------------------------------------------- /scripts/raise_issue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Raises an issue with the specified options. 5 | 6 | Usage example: 7 | 8 | ./raise-issue.py -t "Issue name" -f file -a zaproxy -p changeme 9 | 10 | """ 11 | import argparse 12 | import json 13 | import requests 14 | 15 | def make_github_issue(title, owner, repo, user, password, body=None, assignee=None, milestone=None, labels=None): 16 | '''Create an issue on github.com using the given parameters.''' 17 | # url to create issues via POST 18 | url = 'https://api.github.com/repos/%s/%s/issues' % (owner, repo) 19 | # Create an authenticated session to create the issue 20 | session = requests.Session() 21 | session.auth = (user, password) 22 | # Create our issue 23 | issue = {'title': title, 24 | 'body': body, 25 | 'assignee': assignee} 26 | # 'milestone': milestone, 27 | # 'labels': labels} 28 | # Add the issue to our repository 29 | r = session.post(url, json.dumps(issue)) 30 | if r.status_code == 201: 31 | print 'Successfully created Issue "%s"' % title 32 | else: 33 | print 'Could not create Issue "%s"' % title 34 | print 'Response:', r.content 35 | return r.content 36 | 37 | 38 | def get_args(): 39 | parser = argparse.ArgumentParser(description=__doc__) 40 | 41 | parser.add_argument('-t', '--title', 42 | required=True, 43 | help='Issue title') 44 | 45 | parser.add_argument('-f', '--file', 46 | required=True, 47 | help='File containing the issue body') 48 | 49 | parser.add_argument('-o', '--owner', 50 | default='zaproxy', 51 | help='Repo owner, e.g. zaproxy') 52 | 53 | parser.add_argument('-r', '--repo', 54 | default='zap-admin', 55 | help='Repo, e.g. zap-admin') 56 | 57 | parser.add_argument('-u', '--user', 58 | default='zapbot', 59 | help='User, e.g. zapbot') 60 | 61 | parser.add_argument('-p', '--password', 62 | required=True, 63 | help='Password / credentials') 64 | 65 | parser.add_argument('-a', '--assignee', 66 | required=False, 67 | help='Assigne, e.g. zapbot') 68 | 69 | parsed_args = parser.parse_args() 70 | return vars(parsed_args) 71 | 72 | def main(): 73 | cli_args = get_args() 74 | 75 | with open(cli_args['file'], 'r') as content_file: 76 | content = content_file.read() 77 | 78 | return make_github_issue(cli_args['title'], cli_args['owner'], cli_args['repo'], cli_args['user'], 79 | cli_args['password'], body=content, assignee=cli_args['assignee']) 80 | 81 | 82 | if __name__ == '__main__': 83 | main() 84 | -------------------------------------------------------------------------------- /scripts/report_addons_to_release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Simple script for raising issues with details of any add-ons ready to be published 3 | # Run from the top level directory, eg: 4 | # zap-admin/scripts/report_addons_to_release.sh 5 | # 6 | # It assumed all repos are in the cwd and are up to date 7 | # Suitable credentials should be in the ~/.netrc file 8 | 9 | cd zap-admin 10 | # The ``` are to escape all of the characters in the issue, otherwise it messes up a bit ;) 11 | echo "\`\`\`" > addons_to_release 12 | ./gradlew pendingAddOnReleases >> addons_to_release 13 | echo "\`\`\`" >> addons_to_release 14 | 15 | # Extract the password 16 | netrc=`cat ~/.netrc` 17 | words=( $netrc ) 18 | pwd=${words[5]} 19 | 20 | scripts/raise_issue.py -t "Addons ready to release " -f addons_to_release -a zapbot -p "$pwd" 21 | rm addons_to_release 22 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.zaproxy.common.settings") version "0.5.0" 3 | id("com.diffplug.spotless") version "6.25.0" apply false 4 | } 5 | 6 | rootProject.name = "zap-admin" 7 | -------------------------------------------------------------------------------- /src/main/addons-help-website.txt: -------------------------------------------------------------------------------- 1 | # The IDs of the add-ons that should have the help generated to the website. 2 | 3 | # Main help. 4 | help 5 | 6 | # Remaining add-ons, in alphabetic order. 7 | accessControl 8 | alertFilters 9 | alertReport 10 | allinonenotes 11 | ascanrulesAlpha 12 | ascanrulesBeta 13 | ascanrules 14 | # 3rd-party, does not have help. 15 | # attacksurfacedetector 16 | authhelper 17 | authstats 18 | automation 19 | beanshell 20 | browserView 21 | bruteforce 22 | bugtracker 23 | callgraph 24 | callhome 25 | client 26 | commonlib 27 | communityScripts 28 | custompayloads 29 | database 30 | dev 31 | diff 32 | directorylistv1 33 | directorylistv2_3_lc 34 | directorylistv2_3 35 | domxss 36 | encoder 37 | evalvillain 38 | exim 39 | formhandler 40 | fuzz 41 | fuzzai 42 | fuzzdboffensive 43 | fuzzdb 44 | gettingStarted 45 | graaljs 46 | graphql 47 | groovy 48 | grpc 49 | highlighter 50 | hud 51 | imagelocationscanner 52 | invoke 53 | jruby 54 | jsonview 55 | # 3rd-party, does not have help. 56 | # jwt 57 | jython 58 | kotlin 59 | neonmarker 60 | network 61 | oast 62 | onlineMenu 63 | openapi 64 | packpentester 65 | packscanrules 66 | packscripts 67 | paramdigger 68 | plugnhack 69 | postman 70 | pscan 71 | pscanrulesAlpha 72 | pscanrulesBeta 73 | pscanrules 74 | quickstart 75 | # 3rd-party, does not have help. 76 | # reflect 77 | regextester 78 | replacer 79 | reports 80 | requester 81 | retest 82 | retire 83 | reveal 84 | revisit 85 | saml 86 | scanpolicies 87 | scripts 88 | selenium 89 | sequence 90 | soap 91 | spider 92 | spiderAjax 93 | sqliplugin 94 | sse 95 | svndigger 96 | tips 97 | tokengen 98 | treetools 99 | viewstate 100 | wappalyzer 101 | webdriverlinux 102 | webdrivermacos 103 | webdriverwindows 104 | websocket 105 | zest 106 | 107 | -------------------------------------------------------------------------------- /src/main/crowdin-tasks.yml: -------------------------------------------------------------------------------- 1 | - repo: "zaproxy" 2 | tasks: 3 | - name: "crowdinCopyProjectTranslations" 4 | args: [ "--from=%packages_dir%", "--file-filter=_kaa" ] 5 | 6 | - repo: "zap-core-help" 7 | tasks: 8 | - name: ":addOns:crowdinCopyProjectTranslations" 9 | args: [ "--from=%packages_dir%", "--file-filter=_kaa" ] 10 | - name: "updateHelpSetXmlLangAttr" 11 | 12 | - repo: "zap-extensions" 13 | tasks: 14 | - name: "crowdinCopyProjectTranslations" 15 | args: [ "--from=%packages_dir%", "--file-filter=_kaa" ] 16 | - name: "postProcessLocalizedHelpPages" 17 | - name: "spotlessApply" 18 | 19 | - repo: "community-scripts" 20 | tasks: 21 | - name: "crowdinCopyProjectTranslations" 22 | args: [ "--from=%packages_dir%", "--file-filter=_kaa" ] 23 | - name: "postProcessLocalizedHelpPages" 24 | 25 | - repo: "fuzzdb-offensive" 26 | tasks: 27 | - name: "crowdinCopyProjectTranslations" 28 | args: [ "--from=%packages_dir%", "--file-filter=_kaa" ] 29 | - name: "postProcessLocalizedHelpPages" 30 | 31 | - repo: "zap-hud" 32 | tasks: 33 | - name: "crowdinCopyProjectTranslations" 34 | args: [ "--from=%packages_dir%", "--file-filter=_kaa" ] 35 | - name: "postProcessLocalizedHelpPages" 36 | -------------------------------------------------------------------------------- /src/main/java/org/zaproxy/admin/AddOnsTask.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2018 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.admin; 21 | 22 | import java.io.BufferedInputStream; 23 | import java.io.IOException; 24 | import java.io.InputStream; 25 | import java.nio.file.FileVisitResult; 26 | import java.nio.file.Files; 27 | import java.nio.file.Path; 28 | import java.nio.file.Paths; 29 | import java.nio.file.SimpleFileVisitor; 30 | import java.nio.file.attribute.BasicFileAttributes; 31 | import java.text.Collator; 32 | import java.util.ArrayList; 33 | import java.util.Arrays; 34 | import java.util.List; 35 | import java.util.Locale; 36 | import java.util.Set; 37 | import java.util.TreeSet; 38 | import org.apache.log4j.Level; 39 | import org.apache.log4j.Logger; 40 | import org.apache.log4j.varia.NullAppender; 41 | import org.zaproxy.zap.Version; 42 | import org.zaproxy.zap.control.AddOn; 43 | import org.zaproxy.zap.control.AddOn.Status; 44 | import org.zaproxy.zap.control.ZapAddOnXmlFile; 45 | 46 | /** A task for add-ons in zap-extensions repo. */ 47 | public abstract class AddOnsTask { 48 | 49 | static { 50 | NullAppender na = new NullAppender(); 51 | Logger.getRootLogger().addAppender(na); 52 | Logger.getRootLogger().setLevel(Level.OFF); 53 | } 54 | 55 | private static final String ZAP_ADD_ON_FILE_NAME = "ZapAddOn.xml"; 56 | 57 | protected static Set getAllAddOns() throws IOException { 58 | Set addOns = new TreeSet<>(); 59 | addAddOns(addOns, Paths.get("../zap-extensions/src")); 60 | addAddOns(addOns, Paths.get("../zap-extensions_beta/src")); 61 | addAddOns(addOns, Paths.get("../zap-extensions_alpha/src")); 62 | return addOns; 63 | } 64 | 65 | private static void addAddOns(final Set addOns, Path path) throws IOException { 66 | Files.walkFileTree( 67 | path, 68 | new SimpleFileVisitor() { 69 | 70 | @Override 71 | public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) 72 | throws IOException { 73 | if (isValidZapAddOnXmlFile(file)) { 74 | try (InputStream is = 75 | new BufferedInputStream(Files.newInputStream(file))) { 76 | Path addOnDir = file.getParent(); 77 | String addOnId = addOnDir.getFileName().toString(); 78 | ZapAddOnXmlFile zapAddOnXmlFile = new ZapAddOnXmlFile(is); 79 | addOns.add( 80 | new AddOnData( 81 | addOnDir, 82 | addOnId, 83 | zapAddOnXmlFile.getName(), 84 | zapAddOnXmlFile.getVersion(), 85 | AddOn.Status.valueOf(zapAddOnXmlFile.getStatus()), 86 | zapAddOnXmlFile.getChanges())); 87 | } 88 | } 89 | return FileVisitResult.CONTINUE; 90 | } 91 | }); 92 | } 93 | 94 | private static boolean isValidZapAddOnXmlFile(Path file) { 95 | if (ZAP_ADD_ON_FILE_NAME.equals(file.getFileName().toString())) { 96 | // Ignore example ZapAddOn.xml file 97 | return !file.toString().contains("src/org/zaproxy/zap/extension/ZapAddOn.xml"); 98 | } 99 | return false; 100 | } 101 | 102 | protected static class AddOnData implements Comparable { 103 | 104 | private final Path dir; 105 | private final String id; 106 | private final String name; 107 | private final Version version; 108 | private final AddOn.Status status; 109 | private final List changes; 110 | 111 | public AddOnData( 112 | Path dir, String id, String name, Version version, Status status, String changes) { 113 | super(); 114 | this.dir = dir; 115 | this.id = id; 116 | this.name = name; 117 | this.version = version; 118 | this.status = status; 119 | this.changes = prepareChanges(changes); 120 | } 121 | 122 | public Path getDir() { 123 | return dir; 124 | } 125 | 126 | public String getId() { 127 | return id; 128 | } 129 | 130 | public String getName() { 131 | return name; 132 | } 133 | 134 | public Version getVersion() { 135 | return version; 136 | } 137 | 138 | public AddOn.Status getStatus() { 139 | return status; 140 | } 141 | 142 | public List getChanges() { 143 | return changes; 144 | } 145 | 146 | @Override 147 | public int compareTo(AddOnData other) { 148 | if (other == null) { 149 | return 1; 150 | } 151 | 152 | int result = status.compareTo(other.status); 153 | if (result != 0) { 154 | return -result; 155 | } 156 | 157 | return Collator.getInstance(Locale.ENGLISH).compare(id, other.id); 158 | } 159 | 160 | private static List prepareChanges(String changes) { 161 | List preparedChanges = new ArrayList<>(Arrays.asList(changes.split("
"))); 162 | for (int i = 0; i < preparedChanges.size(); i++) { 163 | String string = preparedChanges.get(i).trim(); 164 | if (string.isEmpty()) { 165 | preparedChanges.remove(i); 166 | i--; 167 | } else { 168 | preparedChanges.set( 169 | i, 170 | string.replaceAll("^\\t*", "") 171 | .replaceAll("^ *", "") 172 | .replaceAll("^(\\r?\\n)*", "") 173 | .replaceAll("(\\r?\\n)*$", "")); 174 | } 175 | } 176 | return preparedChanges; 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/main/java/org/zaproxy/admin/CheckLatestReleaseNotes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2017 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.admin; 21 | 22 | import java.io.BufferedReader; 23 | import java.io.File; 24 | import java.io.FilenameFilter; 25 | import java.io.IOException; 26 | import java.nio.charset.StandardCharsets; 27 | import java.nio.file.Files; 28 | import java.util.HashSet; 29 | import java.util.Set; 30 | import java.util.TreeMap; 31 | 32 | /** 33 | * Command line tool for checking the latest release notes dont contain issues in previous ones. 34 | * 35 | * @author simon 36 | */ 37 | public class CheckLatestReleaseNotes { 38 | 39 | private static final String RELEASE_NOTES_PATH = 40 | "../zap-core-help/addOns/help/src/main/javahelp/contents/releases/"; 41 | 42 | private static Set getIssues(File f) throws IOException { 43 | Set set = new HashSet(); 44 | try (BufferedReader reader = Files.newBufferedReader(f.toPath(), StandardCharsets.UTF_8)) { 45 | while (true) { 46 | String line = reader.readLine(); 47 | if (line == null) { 48 | break; 49 | } 50 | if (line.startsWith("
  • Issue ")) { 51 | String[] split = line.split(" ", 0); 52 | set.add(Integer.parseInt(split[1])); 53 | } 54 | } 55 | } 56 | return set; 57 | } 58 | 59 | public static void main(String[] args) throws IOException { 60 | TreeMap> map = new TreeMap>(); 61 | File relNotesDir = new File(RELEASE_NOTES_PATH); 62 | if (!relNotesDir.exists()) { 63 | System.out.println("No such directory : " + relNotesDir.getAbsolutePath()); 64 | return; 65 | } 66 | File[] relNotes = 67 | relNotesDir.listFiles( 68 | new FilenameFilter() { 69 | 70 | @Override 71 | public boolean accept(File dir, String name) { 72 | return name.endsWith(".html") && !name.startsWith("releases"); 73 | } 74 | }); 75 | 76 | for (File relNote : relNotes) { 77 | map.put(relNote.getName(), getIssues(relNote)); 78 | } 79 | 80 | Set latest = null; 81 | for (String key : map.descendingKeySet()) { 82 | if (latest == null) { 83 | latest = map.get(key); 84 | } else { 85 | for (Integer issue : map.get(key)) { 86 | if (latest.contains(issue)) { 87 | System.out.println("Issue : " + issue + " was included in " + key); 88 | } 89 | } 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/org/zaproxy/admin/CountDownloads.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2015 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.admin; 21 | 22 | import java.io.IOException; 23 | import net.sf.json.JSONArray; 24 | import net.sf.json.JSONObject; 25 | 26 | /** 27 | * Command line tool for printing a summary of the tag assets downloaded from GitHub. 28 | * 29 | * @author simon 30 | */ 31 | public class CountDownloads { 32 | 33 | // Note 100 is the maximum page size allowed - will need to use paging to get any more 34 | private static final String RELEASES_URL = 35 | "https://api.github.com/repos/zaproxy/zaproxy/releases"; 36 | 37 | private static final String TAG_URL = 38 | "https://api.github.com/repos/zaproxy/zaproxy/releases/tags/"; 39 | 40 | private static void parseRelease(JSONObject tag) throws Exception { 41 | if (tag == null) { 42 | return; 43 | } 44 | String tagName = tag.getString("tag_name"); 45 | System.out.println("Tag " + tagName); 46 | 47 | JSONArray assets = tag.getJSONArray("assets"); 48 | int total = 0; 49 | for (int j = 0; j < assets.size(); j++) { 50 | JSONObject asset = assets.getJSONObject(j); 51 | int count = asset.getInt("download_count"); 52 | total += count; 53 | // System.out.println("\t" + asset.getString("name") + " : " + count); 54 | } 55 | System.out.println("\tTotal Downloads: " + total); 56 | } 57 | 58 | private static JSONObject getRelease(String tag) throws Exception { 59 | try { 60 | return JSONObject.fromObject(Utils.readUrl(TAG_URL + tag)); 61 | } catch (IOException e) { 62 | System.out.println("Tag " + tag + "\n\tNo stats"); 63 | return null; 64 | } 65 | } 66 | 67 | public static void main(String[] args) throws Exception { 68 | // Loop through tags, print names 69 | String jsonStr = Utils.readUrl(RELEASES_URL); 70 | 71 | JSONArray json = JSONArray.fromObject(jsonStr); 72 | 73 | if (json.size() >= 100) { 74 | System.out.println( 75 | "WARNING: 100 tags returned - will need to implement paging to get the rest!"); 76 | } 77 | 78 | for (int i = 0; i < json.size(); i++) { 79 | parseRelease(json.getJSONObject(i)); 80 | } 81 | 82 | // Explicitly request the most recent main releases 83 | parseRelease(getRelease("v2.10.0")); 84 | parseRelease(getRelease("v2.9.0")); 85 | parseRelease(getRelease("v2.8.0")); 86 | parseRelease(getRelease("2.7.0")); 87 | parseRelease(getRelease("2.6.0")); 88 | parseRelease(getRelease("2.5.0")); 89 | parseRelease(getRelease("2.4.3")); 90 | parseRelease(getRelease("2.4.2")); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/org/zaproxy/admin/GenerateReleaseNotes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2015 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.admin; 21 | 22 | import java.util.Arrays; 23 | import java.util.Collection; 24 | import java.util.HashMap; 25 | import java.util.List; 26 | import java.util.Map; 27 | import org.apache.commons.text.StringEscapeUtils; 28 | import org.kohsuke.github.GHIssue; 29 | import org.kohsuke.github.GHIssueState; 30 | import org.kohsuke.github.GHLabel; 31 | import org.kohsuke.github.GHRepository; 32 | import org.kohsuke.github.GitHub; 33 | 34 | /** 35 | * Command line tool for generating release notes from GitHub issues and tags. For now the variables 36 | * are hardcoded - at some point they should be made parameters. 37 | * 38 | * @author simon 39 | */ 40 | public class GenerateReleaseNotes { 41 | 42 | static enum IssueType { 43 | dev, 44 | bug, 45 | ignore, 46 | unk 47 | }; 48 | 49 | private static final String REPO = "zaproxy/zaproxy"; 50 | private static final int MILESTONE_NUMBER = 9; 51 | 52 | public static void main(String[] args) throws Exception { 53 | 54 | GHRepository ghRepo = GitHub.connectAnonymously().getRepository(REPO); 55 | List issues = 56 | ghRepo.getIssues(GHIssueState.CLOSED, ghRepo.getMilestone(MILESTONE_NUMBER)); 57 | 58 | Map devIssuesMap = new HashMap(); 59 | Map bugIssuesMap = new HashMap(); 60 | Map unkIssuesMap = new HashMap(); 61 | Map issueTagsMap = new HashMap(); 62 | 63 | for (GHIssue issue : issues) { 64 | IssueType issueType = IssueType.unk; 65 | Collection labels = issue.getLabels(); 66 | StringBuilder sb = new StringBuilder(); 67 | for (GHLabel label : labels) { 68 | String tag = label.getName(); 69 | sb.append(tag); 70 | sb.append(" "); 71 | 72 | if (tag.equalsIgnoreCase("development") 73 | || tag.equalsIgnoreCase("enhancement") 74 | || tag.equalsIgnoreCase("Type-enhancement")) { 75 | issueType = IssueType.dev; 76 | // Carry on in case its got another 'overiding' tag 77 | } 78 | if (tag.equalsIgnoreCase("bug") || tag.equalsIgnoreCase("Type-defect")) { 79 | issueType = IssueType.bug; 80 | // Carry on in case its got another 'overiding' tag 81 | } 82 | if (tag.equalsIgnoreCase("API Client") 83 | || tag.equalsIgnoreCase("Docker") 84 | || tag.equalsIgnoreCase("third-party") 85 | || tag.equalsIgnoreCase("jenkins") 86 | || tag.equalsIgnoreCase("Component-Docs") 87 | || tag.equalsIgnoreCase("invalid") 88 | || tag.equalsIgnoreCase("duplicate") 89 | || tag.equalsIgnoreCase("historic") 90 | || tag.equalsIgnoreCase("wontfix") 91 | || tag.equalsIgnoreCase("minor") 92 | || tag.equalsIgnoreCase("add-on") 93 | || tag.equalsIgnoreCase("Type-Other") 94 | || tag.equalsIgnoreCase("Type-review") 95 | || tag.equalsIgnoreCase("Type-task") 96 | || tag.equalsIgnoreCase("competition") 97 | || tag.equalsIgnoreCase("InsufficientEvidence") 98 | || tag.equalsIgnoreCase("question") 99 | || tag.equalsIgnoreCase("weekly")) { 100 | issueType = IssueType.ignore; 101 | break; 102 | } 103 | } 104 | int number = issue.getNumber(); 105 | issueTagsMap.put(number, sb.toString()); 106 | 107 | switch (issueType) { 108 | case dev: 109 | devIssuesMap.put(number, issue.getTitle()); 110 | break; 111 | case bug: 112 | bugIssuesMap.put(number, issue.getTitle()); 113 | break; 114 | case unk: 115 | unkIssuesMap.put(number, issue.getTitle()); 116 | break; 117 | case ignore: 118 | break; 119 | } 120 | } 121 | 122 | System.out.println("

    Enhancements

    "); 123 | System.out.println("
      "); 124 | Object[] devIssues = devIssuesMap.keySet().toArray(); 125 | Arrays.sort(devIssues); 126 | for (Object key : devIssues) { 127 | printIssue(devIssuesMap, key); 128 | } 129 | System.out.println("
    "); 130 | System.out.println(""); 131 | 132 | System.out.println("

    Bug fixes

    "); 133 | System.out.println("
      "); 134 | Object[] bugIssues = bugIssuesMap.keySet().toArray(); 135 | Arrays.sort(bugIssues); 136 | for (Object key : bugIssues) { 137 | printIssue(bugIssuesMap, key); 138 | } 139 | System.out.println("
    "); 140 | System.out.println(""); 141 | 142 | if (unkIssuesMap.size() > 0) { 143 | System.out.println("Unclassified:"); 144 | System.out.println(""); 145 | Object[] unkIssues = unkIssuesMap.keySet().toArray(); 146 | Arrays.sort(unkIssues); 147 | for (Object key : unkIssues) { 148 | System.out.println("Issue " + key + " : " + unkIssuesMap.get(key)); 149 | System.out.println("\tLink: https://github.com/zaproxy/zaproxy/issues/" + key); 150 | String tags = issueTagsMap.get(key); 151 | if (tags != null && tags.length() > 0) { 152 | System.out.println("\tTags: " + issueTagsMap.get(key)); 153 | } 154 | } 155 | } 156 | } 157 | 158 | private static void printIssue(Map issues, Object number) { 159 | System.out.print("
  • Issue "); 162 | System.out.print(number); 163 | System.out.print(" : "); 164 | System.out.print(StringEscapeUtils.escapeHtml4(issues.get(number))); 165 | System.out.print("
  • \n"); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/main/java/org/zaproxy/admin/PendingAddOnReleases.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2016 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.admin; 21 | 22 | import java.nio.file.Paths; 23 | import java.time.LocalDate; 24 | import java.time.Period; 25 | import java.time.ZoneOffset; 26 | import java.util.Iterator; 27 | import java.util.Set; 28 | import java.util.TreeSet; 29 | import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; 30 | import org.zaproxy.zap.control.AddOn; 31 | import org.zaproxy.zap.control.AddOn.Status; 32 | import org.zaproxy.zap.control.AddOnCollection; 33 | import org.zaproxy.zap.utils.ZapXmlConfiguration; 34 | 35 | public class PendingAddOnReleases extends AddOnsTask { 36 | 37 | private static final String ZAP_VERSIONS_FILE_NAME = "ZapVersions-2.7.xml"; 38 | 39 | public static void main(String[] args) throws Exception { 40 | LocalDate now = LocalDate.now(ZoneOffset.UTC); 41 | boolean showChanges = true; 42 | 43 | ZapXmlConfiguration zapVersions = 44 | new ZapXmlConfiguration(Paths.get(ZAP_VERSIONS_FILE_NAME).toFile()); 45 | AddOnCollection addOnCollection = 46 | new AddOnCollection(zapVersions, AddOnCollection.Platform.daily); 47 | 48 | zapVersions.setExpressionEngine(new XPathExpressionEngine()); 49 | 50 | Set addOns = getAllAddOns(); 51 | int totalAddOns = addOns.size(); 52 | 53 | Set unreleasedAddOns = new TreeSet<>(); 54 | Set unchangedAddOns = new TreeSet<>(); 55 | 56 | for (Iterator it = addOns.iterator(); it.hasNext(); ) { 57 | AddOnData addOnData = it.next(); 58 | AddOn addOn = addOnCollection.getAddOn(addOnData.getId()); 59 | if (addOn == null) { 60 | unreleasedAddOns.add(addOnData); 61 | it.remove(); 62 | } else if (addOn.getVersion().compareTo(addOnData.getVersion()) >= 0) { 63 | it.remove(); 64 | } else if (addOnData.getChanges().isEmpty()) { 65 | unchangedAddOns.add(addOnData); 66 | it.remove(); 67 | } 68 | } 69 | 70 | if (!unreleasedAddOns.isEmpty()) { 71 | System.out.println("============================="); 72 | System.out.println( 73 | "Unreleased add-ons (" + unreleasedAddOns.size() + " of " + totalAddOns + ")"); 74 | System.out.println("============================="); 75 | for (AddOnData addOn : unreleasedAddOns) { 76 | System.out.println( 77 | addOn.getStatus() + "\t" + addOn.getName() + " v" + addOn.getVersion()); 78 | } 79 | System.out.println("=============================\n"); 80 | } 81 | 82 | if (!addOns.isEmpty()) { 83 | System.out.println("======================================="); 84 | System.out.println( 85 | "New versions pending release (" + addOns.size() + " of " + totalAddOns + ")"); 86 | System.out.println("======================================="); 87 | Status currentStatus = null; 88 | for (AddOnData addOn : addOns) { 89 | if (currentStatus != addOn.getStatus()) { 90 | currentStatus = addOn.getStatus(); 91 | System.out.println(currentStatus); 92 | } 93 | LocalDate releaseDate = 94 | LocalDate.parse(zapVersions.getString("/addon_" + addOn.getId() + "/date")); 95 | System.out.println( 96 | " * " 97 | + addOn.getName() 98 | + " v" 99 | + addOn.getVersion() 100 | + " (" 101 | + Period.between(releaseDate, now) 102 | + ")"); 103 | 104 | if (showChanges) { 105 | for (String change : addOn.getChanges()) { 106 | System.out.println(" - " + change); 107 | } 108 | } 109 | } 110 | System.out.println("=======================================\n"); 111 | } 112 | 113 | if (!unchangedAddOns.isEmpty()) { 114 | System.out.println("============================="); 115 | System.out.println( 116 | "Unchanged add-ons (" + unchangedAddOns.size() + " of " + totalAddOns + ")"); 117 | System.out.println("============================="); 118 | for (AddOnData addOn : unchangedAddOns) { 119 | System.out.println( 120 | addOn.getStatus() + "\t" + addOn.getName() + " v" + addOn.getVersion()); 121 | } 122 | System.out.println("=============================\n"); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/org/zaproxy/admin/Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2018 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.admin; 21 | 22 | import java.io.BufferedReader; 23 | import java.io.IOException; 24 | import java.io.InputStreamReader; 25 | import java.net.URI; 26 | import java.net.URISyntaxException; 27 | import java.nio.charset.StandardCharsets; 28 | 29 | /** Utilities for common tasks. */ 30 | public class Utils { 31 | 32 | private Utils() { 33 | // Utility class. 34 | } 35 | 36 | public static String readUrl(String urlString) throws IOException, URISyntaxException { 37 | try (BufferedReader reader = 38 | new BufferedReader( 39 | new InputStreamReader( 40 | new URI(urlString).toURL().openStream(), StandardCharsets.UTF_8))) { 41 | StringBuilder builder = new StringBuilder(); 42 | int read; 43 | char[] chars = new char[1024]; 44 | while ((read = reader.read(chars)) != -1) { 45 | builder.append(chars, 0, read); 46 | } 47 | return builder.toString(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/resources/org/zaproxy/admin/resources/help/contents/addon.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | @@name@@ 7 | 8 | 9 | 10 |

    @@name@@

    11 | @@intro@@ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/resources/org/zaproxy/admin/resources/help/contents/images/cake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zaproxy/zap-admin/ab815105beadb225f19c174024e0d08831b6f353/src/main/resources/org/zaproxy/admin/resources/help/contents/images/cake.png -------------------------------------------------------------------------------- /src/main/resources/org/zaproxy/admin/resources/help/helpset.hs: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | @@name@@ | ZAP Extension 7 | 8 | 9 | top 10 | 11 | 12 | 13 | 14 | TOC 15 | 16 | org.zaproxy.zap.extension.help.ZapTocView 17 | toc.xml 18 | 19 | 20 | 21 | Index 22 | 23 | javax.help.IndexView 24 | index.xml 25 | 26 | 27 | 28 | Search 29 | 30 | javax.help.SearchView 31 | 32 | JavaHelpSearch 33 | 34 | 35 | 36 | 37 | Favorites 38 | 39 | javax.help.FavoritesView 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/main/resources/org/zaproxy/admin/resources/help/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/main/resources/org/zaproxy/admin/resources/help/map.jhm: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | @@icon-map@@ 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/org/zaproxy/admin/resources/help/toc.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/test/java/org/zaproxy/admin/ValidateZapVersionsXmlTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Zed Attack Proxy (ZAP) and its related class files. 3 | * 4 | * ZAP is an HTTP/HTTPS proxy for assessing web application security. 5 | * 6 | * Copyright 2018 The ZAP Development Team 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | package org.zaproxy.admin; 21 | 22 | import static org.assertj.core.api.Assertions.assertThat; 23 | 24 | import java.io.File; 25 | import java.net.URISyntaxException; 26 | import java.net.URL; 27 | import java.nio.file.Paths; 28 | import org.apache.log4j.Logger; 29 | import org.apache.log4j.varia.NullAppender; 30 | import org.junit.jupiter.api.BeforeAll; 31 | import org.junit.jupiter.params.ParameterizedTest; 32 | import org.junit.jupiter.params.provider.EnumSource; 33 | import org.zaproxy.zap.control.AddOnCollection; 34 | import org.zaproxy.zap.control.AddOnCollection.Platform; 35 | import org.zaproxy.zap.utils.ZapXmlConfiguration; 36 | 37 | /** Validates that ZAP is able to load the {@code ZapVersions.xml} files. */ 38 | public class ValidateZapVersionsXmlTest { 39 | 40 | @BeforeAll 41 | public static void suppressLogging() { 42 | Logger.getRootLogger().addAppender(new NullAppender()); 43 | } 44 | 45 | @ParameterizedTest 46 | @EnumSource(value = Platform.class) 47 | public void shouldLoadCurrentVersion(Platform platform) throws Exception { 48 | // Given 49 | File zapVersionsCurr = resource("/ZapVersions-2.7.xml"); 50 | // When 51 | AddOnCollection aoc = 52 | new AddOnCollection(new ZapXmlConfiguration(zapVersionsCurr), platform); 53 | // Then 54 | assertReleaseAndAddOnsPresent(zapVersionsCurr, aoc, platform); 55 | } 56 | 57 | private static void assertReleaseAndAddOnsPresent( 58 | File zapVersionsFile, AddOnCollection aoc, Platform platform) { 59 | assertThat(aoc.getZapRelease()) 60 | .as( 61 | "Release not found in %s using %s platform.", 62 | zapVersionsFile.getName(), platform) 63 | .isNotNull(); 64 | assertThat(aoc.getAddOns()) 65 | .as("No add-ons in %s using %s platform.", zapVersionsFile.getName(), platform) 66 | .isNotEmpty(); 67 | } 68 | 69 | @ParameterizedTest 70 | @EnumSource(value = Platform.class) 71 | public void shouldLoadDevVersion(Platform platform) throws Exception { 72 | // Given 73 | File zapVersionsDev = resource("/ZapVersions-dev.xml"); 74 | // When 75 | AddOnCollection aoc = 76 | new AddOnCollection(new ZapXmlConfiguration(zapVersionsDev), platform); 77 | // Then 78 | assertReleaseAndAddOnsPresent(zapVersionsDev, aoc, platform); 79 | } 80 | 81 | @ParameterizedTest 82 | @EnumSource(value = Platform.class) 83 | public void shouldLoadNonAddOnsVariant(Platform platform) throws Exception { 84 | // Given 85 | File zapVersions = resource("/ZapVersions.xml"); 86 | // When 87 | AddOnCollection aoc = new AddOnCollection(new ZapXmlConfiguration(zapVersions), platform); 88 | // Then 89 | assertThat(aoc.getZapRelease()).isNotNull(); 90 | } 91 | 92 | private static File resource(String path) { 93 | URL resourceURL = ValidateZapVersionsXmlTest.class.getResource(path); 94 | assertThat(resourceURL).as("File %s not found.", path).isNotNull(); 95 | 96 | try { 97 | return Paths.get(resourceURL.toURI()).toFile(); 98 | } catch (URISyntaxException e) { 99 | throw new RuntimeException(e); 100 | } 101 | } 102 | } 103 | --------------------------------------------------------------------------------