diff --git a/.github/CODE_OF_CONDUCT.MD b/.github/CODE_OF_CONDUCT.MD new file mode 100644 index 0000000..12507ab --- /dev/null +++ b/.github/CODE_OF_CONDUCT.MD @@ -0,0 +1,3 @@ +# Code of Conduct + +Please see it in our [Contributing Guidelines](../CONTRIBUTING.md#code-of-conduct). diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.md b/.github/ISSUE_TEMPLATE/BUG_REPORT.md new file mode 100644 index 0000000..300232e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.md @@ -0,0 +1,33 @@ +--- +name: Bug report +about: Create a report to help us improve +--- + + + +## What are the steps to reproduce this issue? + +1. … +2. … +3. … + +## What happens? + +… + +## What were you expecting to happen? + +… + +## Any logs, error output, etc? + +… + +## Any other comments? + +… + +## What versions are you using? + +**Operating System:** … +**Package Version:** … diff --git a/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md new file mode 100644 index 0000000..c10946f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md @@ -0,0 +1,18 @@ +--- +name: Feature Request +about: Request a new feature or enhancement +--- + + + +## Summary + + + +## Detailed Description + + + +## Possible Implementation Ideas + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..e8bd9f9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,29 @@ +# Description + +Please include a summary of the changes and which issue(s) is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +**Please note that all PRs must have tests attached to them** + +IMPORTANT: Please review the [CONTRIBUTING.md](../CONTRIBUTING.md) file for detailed contributing guidelines. + +## Issues + +All PRs must have an accompanied issue. Please make sure you created it and linked it here. + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug Fix +- [ ] Improvement +- [ ] New Feature +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +## Checklist + +- [ ] My code follows the style guidelines of this project [cfformat](../.cfformat.json) +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..f057099 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,3 @@ +# Security Policy + +Please see it in our [Contributing Guidelines](../CONTRIBUTING.md#security-vulnerabilities). diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md new file mode 100644 index 0000000..3bb8adb --- /dev/null +++ b/.github/SUPPORT.md @@ -0,0 +1,3 @@ +# Support & Help + +Please see it in our [Contributing Guidelines](../CONTRIBUTING.md#support-questions). diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index c95d4cf..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,110 +0,0 @@ -name: cbcsrf CI - -# Only on Development we build snapshots -on: - push: - branches: - - development - - master - -env: - MODULE_ID: cbcsrf - -jobs: - ############################################# - # Tests First baby! We fail, no build :( - ############################################# - tests: - uses: ./.github/workflows/tests.yml - secrets: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - - ############################################# - # Build Module - ############################################# - build: - name: Build & Publish - needs: tests - runs-on: ubuntu-20.04 - steps: - - name: Checkout Repository - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Setup Java - uses: actions/setup-java@v3.9.0 - with: - distribution: "temurin" - java-version: "11" - - - name: Setup CommandBox - uses: Ortus-Solutions/setup-commandbox@v2.0.1 - with: - forgeboxAPIKey: ${{ secrets.FORGEBOX_TOKEN }} - - - name: Setup Environment Variables For Build Process - id: current_version - run: | - echo "VERSION=`cat box.json | jq '.version' -r`" >> $GITHUB_ENV - box package set version=@build.version@+@build.number@ - # master or snapshot - echo "Github Ref is $GITHUB_REF" - echo "BRANCH=master" >> $GITHUB_ENV - if [ $GITHUB_REF == 'refs/heads/development' ] - then - echo "BRANCH=development" >> $GITHUB_ENV - fi - - - name: Build ${{ env.MODULE_ID }} - run: | - box install commandbox-docbox - box task run taskfile=build/Build target=run :version=${{ env.VERSION }} :projectName=${{ env.MODULE_ID }} :buildID=${{ github.run_number }} :branch=${{ env.BRANCH }} - - - name: Upload Build Artifacts - if: success() - uses: actions/upload-artifact@v3.1.1 - with: - name: ${{ env.MODULE_ID }} - path: | - .artifacts/**/* - - - name: Upload Binaries to S3 - uses: jakejarvis/s3-sync-action@master - with: - args: --acl public-read - env: - AWS_S3_BUCKET: "downloads.ortussolutions.com" - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }} - SOURCE_DIR: ".artifacts/${{ env.MODULE_ID }}" - DEST_DIR: "ortussolutions/coldbox-modules/${{ env.MODULE_ID }}" - - - name: Upload API Docs to S3 - uses: jakejarvis/s3-sync-action@master - with: - args: --acl public-read - env: - AWS_S3_BUCKET: "apidocs.ortussolutions.com" - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }} - SOURCE_DIR: ".tmp/apidocs" - DEST_DIR: "coldbox-modules/${{ env.MODULE_ID }}/${{ env.VERSION }}" - - - name: Publish To ForgeBox - run: | - cd .tmp/${{ env.MODULE_ID }} - cat box.json - box forgebox publish - - - name: Inform Slack - if: ${{ always() }} - uses: rtCamp/action-slack-notify@v2 - env: - SLACK_CHANNEL: coding - SLACK_COLOR: ${{ job.status }} # or a specific color like 'green' or '#ff00ff' - SLACK_ICON_EMOJI: ":bell:" - SLACK_MESSAGE: '${{ env.MODULE_ID }} Built with ${{ job.status }}!' - SLACK_TITLE: "${{ env.MODULE_ID }} Build" - SLACK_USERNAME: CI - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml new file mode 100644 index 0000000..b47207b --- /dev/null +++ b/.github/workflows/cron.yml @@ -0,0 +1,10 @@ +name: Daily Tests + +on: + schedule: + - cron: '0 0 * * *' # Runs at 00:00 UTC every day + +jobs: + tests: + uses: ./.github/workflows/tests.yml + secrets: inherit diff --git a/.github/workflows/gh-release.yml b/.github/workflows/gh-release.yml deleted file mode 100644 index 9f9c254..0000000 --- a/.github/workflows/gh-release.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Publish Github Release -name: Github Release - -on: - push: - tags: - - v[0-9]+.* - -jobs: - create-release: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: taiki-e/create-gh-release-action@v1.6.1 - with: - # Produced by the build/Build.cfc - changelog: changelog.md - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 702c815..b0bf721 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -13,22 +13,16 @@ on: jobs: tests: uses: ./.github/workflows/tests.yml - secrets: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + secrets: inherit # Format PR - format: - name: Format - runs-on: ubuntu-20.04 + format_check: + name: Checks Source Code Formatting + runs-on: ubuntu-24.04 steps: - name: Checkout Repository - uses: actions/checkout@v3.2.0 + uses: actions/checkout@v4 - uses: Ortus-Solutions/commandbox-action@v1.0.2 with: - cmd: run-script format - - - name: Commit Format Changes - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: Apply cfformat changes + cmd: run-script format:check diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..c9069d6 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,207 @@ +name: Build a Release + +on: + # If you push to master|main this will trigger a stable release + push: + branches: + - master + - main + + # Reusable workflow : Usually called by a `snapshot` workflow + workflow_call: + inputs: + snapshot: + description: 'Is this a snapshot build?' + required: false + default: false + type: boolean + + # Manual Trigger + workflow_dispatch: +env: + MODULE_ID: ${{ github.event.repository.name }} + JDK: 21 + SNAPSHOT: ${{ inputs.snapshot || false }} + BUILD_ID: ${{ github.run_number }} + +jobs: + ########################################################################################## + # Build & Publish + ########################################################################################## + build: + name: Build & Publish + runs-on: ubuntu-24.04 + permissions: + checks: write + pull-requests: write + contents: write + issues: write + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Setup CommandBox + uses: Ortus-Solutions/setup-commandbox@v2.0.1 + with: + forgeboxAPIKey: ${{ secrets.FORGEBOX_TOKEN }} + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: ${{ env.JDK }} + + - name: "Setup Environment Variables For Build Process" + id: current_version + run: | + echo "VERSION=`cat box.json | jq '.version' -r`" >> $GITHUB_ENV + box package set version=@build.version@+@build.number@ + # master or snapshot + echo "Github Ref is $GITHUB_REF" + echo "BRANCH=master" >> $GITHUB_ENV + if [ $GITHUB_REF == 'refs/heads/development' ] + then + echo "BRANCH=development" >> $GITHUB_ENV + fi + + - name: Update changelog [unreleased] with latest version + uses: thomaseizinger/keep-a-changelog-new-release@3.1.0 + if: env.SNAPSHOT == 'false' + with: + changelogPath: ./changelog.md + tag: v${{ env.VERSION }} + + - name: Build ${{ env.MODULE_ID }} + run: | + npm install -g markdownlint-cli + markdownlint changelog.md --fix + box install commandbox-docbox + box task run taskfile=build/Build target=run :version=${{ env.VERSION }} :projectName=${{ env.MODULE_ID }} :buildID=${{ env.BUILD_ID }} :branch=${{ env.BRANCH }} + + - name: Commit Changelog [unreleased] with latest version + uses: EndBug/add-and-commit@v9.1.4 + if: env.SNAPSHOT == 'false' + with: + author_name: Github Actions + author_email: info@ortussolutions.com + message: 'Finalized changelog for v${{ env.VERSION }}' + add: changelog.md + + - name: Tag Version + uses: rickstaa/action-create-tag@v1.7.2 + if: env.SNAPSHOT == 'false' + with: + tag: "v${{ env.VERSION }}" + force_push_tag: true + message: "Latest Release v${{ env.VERSION }}" + + - name: Upload Build Artifacts + if: success() + uses: actions/upload-artifact@v4 + with: + name: ${{ env.MODULE_ID }} + path: | + .artifacts/**/* + changelog.md + + - name: Upload Binaries to S3 + uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read + env: + AWS_S3_BUCKET: "downloads.ortussolutions.com" + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }} + SOURCE_DIR: ".artifacts/${{ env.MODULE_ID }}" + DEST_DIR: "ortussolutions/coldbox-modules/${{ env.MODULE_ID }}" + + - name: Upload API Docs to S3 + uses: jakejarvis/s3-sync-action@master + with: + args: --acl public-read + env: + AWS_S3_BUCKET: "apidocs.ortussolutions.com" + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_ACCESS_SECRET }} + SOURCE_DIR: ".tmp/apidocs" + DEST_DIR: "coldbox-modules/${{ env.MODULE_ID }}/${{ env.VERSION }}" + + - name: Publish To ForgeBox + run: | + cd .tmp/${{ env.MODULE_ID }} + cat box.json + box forgebox publish --force + + - name: Create Github Release + uses: taiki-e/create-gh-release-action@v1.8.2 + continue-on-error: true + if: env.SNAPSHOT == 'false' + with: + title: ${{ env.VERSION }} + changelog: changelog.md + token: ${{ secrets.GITHUB_TOKEN }} + ref: refs/tags/v${{ env.VERSION }} + + - name: Inform Slack + if: ${{ always() }} + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_CHANNEL: coding + SLACK_COLOR: ${{ job.status }} # or a specific color like 'green' or '#ff00ff' + SLACK_ICON_EMOJI: ":bell:" + SLACK_MESSAGE: "Module ${{ env.MODULE_ID }} v${{ env.VERSION }} Built with ${{ job.status }}!" + SLACK_TITLE: "ColdBox Module ${{ env.MODULE_ID }}" + SLACK_USERNAME: CI + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} + + ########################################################################################## + # Prep Next Release + ########################################################################################## + prep_next_release: + name: Prep Next Release + if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main' + runs-on: ubuntu-24.04 + needs: [ build ] + permissions: + checks: write + pull-requests: write + contents: write + issues: write + steps: + # Checkout development + - name: Checkout Repository + uses: actions/checkout@v4 + with: + ref: development + + - name: Setup CommandBox + uses: Ortus-Solutions/setup-commandbox@v2.0.1 + with: + forgeboxAPIKey: ${{ secrets.FORGEBOX_TOKEN }} + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: ${{ env.MODULE_ID }} + path: .tmp + + # Copy the changelog to the development branch + - name: Copy Changelog + run: | + cp .tmp/changelog.md changelog.md + + # Bump to next version + - name: Bump Version + run: | + box bump --minor --!TagVersion + + # Commit it back to development + - name: Commit Version Bump + uses: EndBug/add-and-commit@v9.1.4 + with: + author_name: Github Actions + author_email: info@ortussolutions.com + message: 'Version bump' + add: | + box.json + changelog.md diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml new file mode 100644 index 0000000..50c8392 --- /dev/null +++ b/.github/workflows/snapshot.yml @@ -0,0 +1,58 @@ +name: Build Snapshot + +on: + push: + branches: + - 'development' + + workflow_dispatch: + +# Unique group name per workflow-branch/tag combo +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + ########################################################################################## + # Module Tests + ########################################################################################## + tests: + secrets: inherit + uses: ./.github/workflows/tests.yml + + ########################################################################################## + # Format Source Code + ########################################################################################## + format: + name: Code Auto-Formatting + runs-on: ubuntu-24.04 + permissions: + contents: write + checks: write + steps: + - uses: actions/checkout@v4 + + - name: Auto-format + uses: Ortus-Solutions/commandbox-action@v1.0.2 + with: + cmd: run-script format + + - name: Commit Format Changes + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Apply cfformat changes + + ########################################################################################## + # Release it + ########################################################################################## + release: + uses: ./.github/workflows/release.yml + needs: [ tests, format ] + secrets: inherit + permissions: + checks: write + pull-requests: write + contents: write + issues: write + with: + snapshot: true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c0c99a6..c01b7cb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -10,31 +10,50 @@ on: jobs: tests: name: Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 env: DB_USER: root DB_PASSWORD: root + continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: - cfengine: [ "lucee@5", "adobe@2018", "adobe@2021" ] + cfengine: [ "boxlang-cfml@1", "lucee@5", "lucee@6", "adobe@2021", "adobe@2023" ] + coldboxVersion: [ "^7.0.0" ] + experimental: [ false ] + # Experimental: ColdBox BE vs All Engines + include: + - coldboxVersion: "be" + cfengine: "lucee@5" + experimental: true + - coldboxVersion: "be" + cfengine: "lucee@6" + experimental: true + - coldboxVersion: "be" + cfengine: "adobe@2021" + experimental: true + - coldboxVersion: "be" + cfengine: "adobe@2023" + experimental: true + - coldboxVersion: "be" + cfengine: "boxlang-cfml@1" + experimental: true steps: - name: Checkout Repository - uses: actions/checkout@v3.2.0 + uses: actions/checkout@v4 + + # DATABASE SETUP: uncomment if you need to setup a database + # - name: Setup Database and Fixtures + # run: | + # sudo systemctl start mysql.service + # mysql -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }} -e 'CREATE DATABASE mementifier;' + # mysql -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }} < test-harness/tests/resources/coolblog.sql - name: Setup Java - uses: actions/setup-java@v3.9.0 + uses: actions/setup-java@v4 with: distribution: "temurin" - java-version: "11" - - - name: Setup Database and Fixtures - run: | - #sudo systemctl start mysql.service - # Create Database - #mysql -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }} -e 'CREATE DATABASE cbsecurity;' - # Import Database - #mysql -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }} < test-harness/tests/resources/cbsecurity.sql + java-version: "21" - name: Setup Environment For Testing Process run: | @@ -54,7 +73,10 @@ jobs: - name: Install Dependencies run: | - box run-script install:dependencies + box install + cd test-harness + box package set dependencies.coldbox=${{ matrix.coldboxVersion }} + box install - name: Start ${{ matrix.cfengine }} Server run: | @@ -65,33 +87,32 @@ jobs: run: | mkdir -p test-harness/tests/results box testbox run --verbose outputFile=test-harness/tests/results/test-results outputFormats=json,antjunit - ls -lR test-harness/tests - name: Publish Test Results - uses: EnricoMi/publish-unit-test-result-action@v1 + uses: EnricoMi/publish-unit-test-result-action@v2 if: always() with: - files: test-harness/tests/results/**/*.xml - check_name: "${{ matrix.cfengine }} Test Results" + junit_files: test-harness/tests/results/**/*.xml + check_name: "${{ matrix.cfengine }} ColdBox ${{ matrix.coldboxVersion }} Test Results" - name: Upload Test Results to Artifacts if: always() - uses: actions/upload-artifact@v3.1.1 + uses: actions/upload-artifact@v4 with: - name: test-results-${{ matrix.cfengine }} + name: test-results-${{ matrix.cfengine }}-${{ matrix.coldboxVersion }} path: | test-harness/tests/results/**/* - - name: Failure Debugging Log + - name: Show Server Log On Failures if: ${{ failure() }} run: | box server log serverConfigFile="server-${{ matrix.cfengine }}.json" - - name: Upload Debugging Log To Artifacts + - name: Upload Debug Logs To Artifacts if: ${{ failure() }} - uses: actions/upload-artifact@v3.1.1 + uses: actions/upload-artifact@v4 with: - name: Failure Debugging Info - ${{ matrix.cfengine }} + name: Failure Debugging Info - ${{ matrix.cfengine }} - ${{ matrix.coldboxVersion }} path: | .engine/**/logs/* .engine/**/WEB-INF/cfusion/logs/* @@ -105,6 +126,6 @@ jobs: SLACK_COLOR: ${{ job.status }} # or a specific color like 'green' or '#ff00ff' SLACK_ICON_EMOJI: ":bell:" SLACK_MESSAGE: '${{ github.repository }} tests failed :cry:' - SLACK_TITLE: ${{ github.repository }} Tests For ${{ matrix.cfengine }} failed + SLACK_TITLE: ${{ github.repository }} Tests For ${{ matrix.cfengine }} with ColdBox ${{ matrix.coldboxVersion }} failed SLACK_USERNAME: CI SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.markdownlint.json b/.markdownlint.json index 3707fcb..21bc843 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -11,5 +11,6 @@ "no-duplicate-header" : { "siblings_only" : true }, + "no-duplicate-heading" : false, "no-inline-html" : false } diff --git a/.vscode/settings.json b/.vscode/settings.json index 2506a17..063461e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,14 +1,31 @@ { + "cflint.enabled": false, "cfml.mappings": [ { "logicalPath": "/coldbox", - "directoryPath": "./test-harness/coldbox", - "isPhysicalDirectoryPath": false + "directoryPath": "./coldbox", + "isPhysicalDirectoryPath" :false }, { "logicalPath": "/testbox", - "directoryPath": "./test-harness/testbox", - "isPhysicalDirectoryPath": false + "directoryPath": "./testbox", + "isPhysicalDirectoryPath" :false } - ] + ], + "sqltools.connections": [ + { + "mysqlOptions": { + "authProtocol": "xprotocol" + }, + "previewLimit": 50, + "server": "localhost", + "port": 33060, + "driver": "MySQL", + "name": "local-mysql8", + "group": "local", + "database": "cbsecurity", + "username": "root", + "connectionTimeout": 1000 + } + ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..8921b11 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,33 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Run CommandBox Task", + "type": "shell", + "command": "box task run ${relativeFile}", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + }, + { + "label": "Run TestBox Bundle", + "type": "shell", + "command": "box testbox run bundles=${relativeFile}", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "new" + }, + "problemMatcher": [] + } + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9e0f1be --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,88 @@ +# CBSecurity Contributing Guide + +Hola amigo! I'm really excited that you are interested in contributing to our project. Before submitting your contribution, please make sure to take a moment and read through the following guidelines: + +- [Code Of Conduct](#code-of-conduct) +- [Bug Reporting](#bug-reporting) +- [Support Questions](#support-questions) +- [Security Vulnerabilities](#security-vulnerabilities) +- [Language Compatibility](#language-compatibility) +- [Coding Styles \& Formatting](#coding-styles--formatting) +- [CFC Docs With DocBox](#cfc-docs-with-docbox) +- [Financial Contributions](#financial-contributions) +- [Contributors](#contributors) + +## Code Of Conduct + +This project is open source, and as such, the maintainers give their free time to build and maintain the source code held within. They make the code freely available in the hope that it will be of use to other developers and/or businesses. Please be considerate towards maintainers when raising issues or presenting pull requests. **We all follow the Golden Rule: Do to others as you want them to do to you.** + +- As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. +- Participants will be tolerant of opposing views. +- Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. +- Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. +- When interpreting the words and actions of others, participants should always assume good intentions. Emotions cannot be derived from textual representations. +- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. + +## Bug Reporting + +Each of the main standalone frameworks in ColdBox has its separate locations for submitting bug reports. Please make sure also that if you submit a pull request, you link it to the appropriate issue. + +https://github.com/coldbox-modules/cbsecurity + +If you file a bug report, your issue should contain a title, a clear description of the issue, a way to replicate the issue, and any support files that we might need to replicate your issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix for it. All issues that do not contain a way to replicate will not be addressed. + +## Support Questions + +If you have any questions on usage, professional support or just ideas to bounce off the maintainers, please do not create an issue. Leverage our support channels first. + +- Ortus Community Discourse: https://community.ortussolutions.com/ +- Box Slack Team : https://boxteam.ortussolutions.com/ +- Professional Support : https://www.ortussolutions.com/services/support + +## Security Vulnerabilities + +If you discover a security vulnerability, please send an email to the development team at [security@ortussolutions.com](mailto:security@ortussolutions.com?subject=security) and make sure you report it to the `#security` channel in our Box Team Slack Channel. All security vulnerabilities will be promptly addressed. + +## Language Compatibility + +Please make sure your code runs on the following CFML Engines: + +- Lucee 5+ +- Adobe ColdFusion 2018+ + +## Coding Styles & Formatting + +We are big on coding styles and have included a `.cfformat.json` in the root of the project so that you can run the formatting tools and CommandBox scripts: + +```bash +# Format everything +box run-script format + +# Start a watcher, type away, save and auto-format for you +box run-script format: watch +``` + +We recommend that anytime you hack on the core you start the formatter watcher (`box run-script format:watch`). This will monitor your changes and auto-format your code for you. + +You can also see the Ortus Coding Standards you must follow here: https://github.com/Ortus-Solutions/coding-standards. + +## CFC Docs With DocBox + +All CFCs are self-documenting and we leverage [DocBox](https://docbox.ortusbooks.com/) to document the entire software. All functions must be properly documented using the DocBox syntax: https://docbox.ortusbooks.com/getting-started/annotating-your-code + +## Financial Contributions + +You can support ColdBox and all of our Open Source initiatives at Ortus Solutions by becoming a patreon. You can also get lots of goodies and services depending on the level of contributions. + +- [Become a backer or sponsor on Patreon](https://www.patreon.com/ortussolutions) +- [One-time donations via PayPal](https://www.paypal.com/paypalme/ortussolutions) + +## Contributors + +Thank you to all the people who have already contributed to ColdBox! We: heart: : heart: : heart: love you! + + + + + +Made with [contributors-img](https://contrib.rocks) diff --git a/box.json b/box.json index e9404de..a53f6fd 100644 --- a/box.json +++ b/box.json @@ -1,6 +1,6 @@ { "name":"ColdBox Cross Site Request Forgery (CSRF)", - "version":"3.1.0", + "version":"3.2.0", "location":"https://downloads.ortussolutions.com/ortussolutions/coldbox-modules/cbcsrf/@build.version@/cbcsrf-@build.version@.zip", "author":"Ortus Solutions.com ", "slug":"cbcsrf", @@ -27,10 +27,9 @@ "cbstorages":"^3.0.0" }, "devDependencies":{ + "commandbox-boxlang":"*", "commandbox-cfformat":"*", - "commandbox-docbox":"*", - "commandbox-dotenv":"*", - "commandbox-cfconfig":"*" + "commandbox-docbox":"*" }, "ignore":[ "**/.*", @@ -44,9 +43,15 @@ "build:module":"task run taskFile=build/Build.cfc :projectName=`package show slug` :version=`package show version`", "build:docs":"task run taskFile=build/Build.cfc target=docs :projectName=`package show slug` :version=`package show version`", "release":"recipe build/release.boxr", - "format":"cfformat run handlers,models,test-harness/tests/specs/,ModuleConfig.cfc", - "format:watch":"cfformat watch handlers,models,test-harness/tests/specs/,ModuleConfig.cfc", - "format:check":"cfformat check handlers,models,test-harness/tests/specs/,ModuleConfig.cfc", - "install:dependencies":"install && cd test-harness && install" + "format":"cfformat run handlers/,interceptors/,models/,test-harness/tests/specs,ModuleConfig.cfc --overwrite", + "format:watch":"cfformat watch handlers/,interceptors/,models/,test-harness/tests/specs,ModuleConfig.cfc ./.cfformat.json", + "format:check":"cfformat check handlers/,interceptors/,models/,test-harness/tests/specs,ModuleConfig.cfc", + "install:dependencies":"install && cd test-harness && install", + "start:lucee" : "server start serverConfigFile=server-lucee@5.json", + "start:2021" : "server start serverConfigFile=server-adobe@2021.json", + "stop:lucee" : "server stop serverConfigFile=server-lucee@5.json", + "stop:2021" : "server stop serverConfigFile=server-adobe@2021.json", + "logs:lucee" : "server log serverConfigFile=server-lucee@5.json --follow", + "logs:2021" : "server log serverConfigFile=server-adobe@2021.json --follow" } } diff --git a/build/Build.cfc b/build/Build.cfc index 926cce1..b15a671 100644 --- a/build/Build.cfc +++ b/build/Build.cfc @@ -12,6 +12,7 @@ component { variables.cwd = getCWD().reReplace( "\.$", "" ); variables.artifactsDir = cwd & "/.artifacts"; variables.buildDir = cwd & "/.tmp"; + variables.apidDocsDir = variables.buildDir & "/apidocs"; variables.apiDocsURL = "http://localhost:60299/apidocs/"; variables.testRunner = "http://localhost:60299/tests/runner.cfm"; @@ -31,7 +32,8 @@ component { // Cleanup + Init Build Directories [ variables.buildDir, - variables.artifactsDir + variables.artifactsDir, + variables.apidDocsDir ].each( function( item ){ if ( directoryExists( item ) ) { directoryDelete( item, true ); @@ -76,9 +78,6 @@ component { // checksums buildChecksums(); - // Build latest changelog - latestChangelog(); - // Finalize Message print .line() @@ -130,9 +129,7 @@ component { ) .toConsole(); - // Prepare exports directory - variables.exportsDir = variables.artifactsDir & "/#projectName#/#arguments.version#"; - directoryCreate( variables.exportsDir, true, true ); + ensureExportDir( argumentCollection = arguments ); // Project Build Dir variables.projectBuildDir = variables.buildDir & "/#projectName#"; @@ -200,11 +197,12 @@ component { version = "1.0.0", outputDir = ".tmp/apidocs" ){ + ensureExportDir( argumentCollection = arguments ); + // Create project mapping fileSystemUtil.createMapping( arguments.projectName, variables.cwd ); // Generate Docs print.greenLine( "Generating API Docs, please wait..." ).toConsole(); - directoryCreate( arguments.outputDir, true, true ); command( "docbox generate" ) .params( @@ -228,27 +226,6 @@ component { ); } - /** - * Build the latest changelog file: changelog-latest.md - */ - function latestChangelog(){ - print.blueLine( "Building latest changelog..." ).toConsole(); - - if ( !fileExists( variables.cwd & "changelog.md" ) ) { - return error( "Cannot continue building, changelog.md file doesn't exist!" ); - } - - fileWrite( - variables.cwd & "changelog-latest.md", - fileRead( variables.cwd & "changelog.md" ).split( "----" )[ 2 ].trim() & chr( 13 ) & chr( 10 ) - ); - - print - .greenLine( "Latest changelog file created at `changelog-latest.md`" ) - .line() - .line( fileRead( variables.cwd & "changelog-latest.md" ) ); - } - /********************************************* PRIVATE HELPERS *********************************************/ /** @@ -315,4 +292,18 @@ component { return ( createObject( "java", "java.lang.System" ).getProperty( "cfml.cli.exitCode" ) ?: 0 ); } + /** + * Ensure the export directory exists at artifacts/NAME/VERSION/ + */ + private function ensureExportDir( + required projectName, + version = "1.0.0" + ){ + if ( structKeyExists( variables, "exportsDir" ) && directoryExists( variables.exportsDir ) ){ + return; + } + // Prepare exports directory + variables.exportsDir = variables.artifactsDir & "/#projectName#/#arguments.version#"; + directoryCreate( variables.exportsDir, true, true ); + } } diff --git a/build/release.boxr b/build/release.boxr index e216f22..a63f2cc 100755 --- a/build/release.boxr +++ b/build/release.boxr @@ -7,19 +7,8 @@ # Merge development into it for release !git merge --no-ff development -# Tag the master repo with the version from box.json -!git tag v`box package show version` - # Push all branches back out to github !git push origin --all -# Push all tags -!git push origin --tags - # Check development again !git checkout -f development - -# Bump to prepare for a new release, do minor, change if needed and don't tag -bump --minor --!tagVersion -!git commit -a -m "version bump" -!git push origin development \ No newline at end of file diff --git a/changelog.md b/changelog.md index 34998f9..a1a97bd 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ---- +## [Unreleased] + +### Added + +- BoxLang certification +- Github Actions updates +- ColdBox 7 Testing + ## [3.1.0] => 2023-FEB-17 ### Added @@ -15,8 +23,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Updates for Adobe 2021 server installations ----- - ## [3.0.0] => 2022-OCT-10 ### Added @@ -27,24 +33,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Dropped ACF 2016 ----- - ## [2.3.1] => 2021-NOV-10 ### Fixed * Fixed cfformat locations on `box.json` ----- - ## [2.3.0] => 2021-SEP-02 ### Added/Compatiblity * New setting: `enableAuthTokenRotator` which defaults to **false**, unlike previously which was **true**. This allows for rotation of keys for csrf tokens on login and logout if you are using cbauth via the new interceptor: `AuthRotator`. Make sure you turn this flag to **true** to keep the previous version functionality. ----- - ## [2.2.0] => 2021-JUL-21 ### Added @@ -59,8 +59,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * ensure `actionMarkedToSkip()` returns `false` when the handler is empty ----- - ## [2.1.0] => 2020-SEP-09 ### Added @@ -74,14 +72,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Null checks on `defaultValue` in case it's passed as an empty string ----- - ## [2.0.1] => 2020-APR-06 * Deactivate the verifier by default ----- - ## [2.0.0] => 2020-APR-02 ### Features @@ -100,23 +94,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * All methods signatures have changed, please see the readme for the updated methods ----- - ## [1.1.0] * Travis updates * Build updates * DocBox migration ----- - ## [1.0.1] * production ignore lists * Unloading of helpers ----- - ## [1.0.0] * Create first module version diff --git a/handlers/Main.cfc b/handlers/Main.cfc index 9419400..ae389ca 100644 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -2,7 +2,7 @@ * Handler to generate csrf tokens for a user according to key * This handler is secured by default if using cbGuard or cbSecurity */ -component secured{ +component secured { property name="settings" inject="coldbox:moduleSettings:cbcsrf"; @@ -19,4 +19,4 @@ component secured{ return csrfToken( rc.key ?: "default" ); } -} \ No newline at end of file +} diff --git a/interceptors/VerifyCsrf.cfc b/interceptors/VerifyCsrf.cfc index dcd0718..9b28d6b 100644 --- a/interceptors/VerifyCsrf.cfc +++ b/interceptors/VerifyCsrf.cfc @@ -1,6 +1,6 @@ /** -* Verifies the CSRF token on all non-GET requests -*/ + * Verifies the CSRF token on all non-GET requests + */ component extends="coldbox.system.Interceptor" accessors="true" { /* ********************************************************************* @@ -8,13 +8,16 @@ component extends="coldbox.system.Interceptor" accessors="true" { ********************************************************************* */ property name="handlerService" inject="coldbox:handlerService"; - property name="cbcsrf" inject="@cbcsrf"; + property name="cbcsrf" inject="@cbcsrf"; - /* ********************************************************************* - ** Properties - ********************************************************************* */ + /* ********************************************************************* + ** Properties + ********************************************************************* */ - property name="isTestMode" type="boolean" default="false"; + property + name ="isTestMode" + type ="boolean" + default="false"; /** * Configure the interceptor @@ -26,81 +29,83 @@ component extends="coldbox.system.Interceptor" accessors="true" { /** * Fire before event execution * - * @event + * @event * @interceptData - * @buffer - * @rc - * @prc + * @buffer + * @rc + * @prc */ - public void function preProcess( event, interceptData, rc, prc ) { + public void function preProcess( event, interceptData, rc, prc ){ // Are we in test mode? then skip - if( variables.isTestMode ){ - if( log.canDebug() ){ + if ( variables.isTestMode ) { + if ( log.canDebug() ) { log.debug( "cbcsrf Verify skipped, we are in integration test mode" ); } - return; + return; } // If it's a GET/HEAD/OPTIONS pass it - if ( listFindNoCase( "GET,OPTIONS,HEAD", event.getHTTPMethod() ) ) { - if( log.canDebug() ){ - log.debug( "cbcsrf Verify skipped due to HTTP method: #event.getHTTPMethod()#=>#event.getCurrentEvent()#" ); + if ( listFindNoCase( "GET,OPTIONS,HEAD", event.getHTTPMethod() ) ) { + if ( log.canDebug() ) { + log.debug( + "cbcsrf Verify skipped due to HTTP method: #event.getHTTPMethod()#=>#event.getCurrentEvent()#" + ); } - return; + return; } // is the incoming event is in the skipped events? - if( - variables.cbcsrf.getSettings() + if ( + variables.cbcsrf + .getSettings() .verifyExcludes .filter( function( item ){ // If found, then don't return it return !reFindNoCase( item, event.getCurrentEvent() ); - } ).len() != variables.cbcsrf.getSettings().verifyExcludes.len() - ){ - if( log.canDebug() ){ - log.debug( "cbcsrf Verify skipped as event: #event.getCurrentEvent()# is in the verify excludes list." ); + } ) + .len() != variables.cbcsrf.getSettings().verifyExcludes.len() + ) { + if ( log.canDebug() ) { + log.debug( + "cbcsrf Verify skipped as event: #event.getCurrentEvent()# is in the verify excludes list." + ); } return; } // Does the event have an annotation - if ( actionMarkedToSkip( arguments.event ) ) { - if( log.canDebug() ){ - log.debug( "cbcsrf Verify skipped as action has been annotated to skip: #event.getCurrentEvent()#" ); + if ( actionMarkedToSkip( arguments.event ) ) { + if ( log.canDebug() ) { + log.debug( + "cbcsrf Verify skipped as action has been annotated to skip: #event.getCurrentEvent()#" + ); } - return; + return; } // Do we have an incoming token in the form or header - if ( ! event.valueExists( "csrf" ) && ! event.getHTTPHeader( "x-csrf-token", "" ).len() ) { - throw( - type = "TokenNotFoundException", - message = "The CSRF token was not included." - ); - } + if ( !event.valueExists( "csrf" ) && !event.getHTTPHeader( "x-csrf-token", "" ).len() ) { + throw( type = "TokenNotFoundException", message = "The CSRF token was not included." ); + } // Get it, put it in prc scope and Verify the token prc.csrfToken = event.getValue( "csrf", event.getHTTPHeader( "x-csrf-token", "" ) ); - if ( ! variables.cbcsrf.verify( prc.csrfToken ) ) { - throw( - type = "TokenMismatchException", - message = "The CSRF token is invalid." - ); + if ( !variables.cbcsrf.verify( prc.csrfToken ) ) { + throw( type = "TokenMismatchException", message = "The CSRF token is invalid." ); } - if( log.canDebug() ){ + if ( log.canDebug() ) { log.debug( "cbcsrf verified for #event.getCurrentEvent()#" ); } - } + } /** * Are we skipping the action or not due to the skipCsrf annotation? * - * @event + * @event * @interceptData */ - private boolean function actionMarkedToSkip( required event ) { + private boolean function actionMarkedToSkip( required event ){ var handlerBean = handlerService.getHandlerBean( arguments.event.getCurrentEvent() ); if ( handlerBean.getHandler() == "" ) { return false; @@ -112,6 +117,6 @@ component extends="coldbox.system.Interceptor" accessors="true" { } return handlerBean.getActionMetadata( "skipCsrf", false ); - } + } } diff --git a/models/cbcsrf.cfc b/models/cbcsrf.cfc index c428855..e08bffc 100644 --- a/models/cbcsrf.cfc +++ b/models/cbcsrf.cfc @@ -39,7 +39,7 @@ component accessors="true" singleton { /** * Provides a random token and stores it in cbstorages. You can also provide a specific key to store. * - * @key A random token is generated for the key provided. + * @key A random token is generated for the key provided. * @forceNew If set to true, a new token is generated every time the function is called. If false, in case a token exists for the key, the same key is returned. * * @return The csrf token @@ -91,14 +91,11 @@ component accessors="true" singleton { * Validates the given token against the same stored in the session for a specific key. * * @token Token that to be validated against the token stored in the session. - * @key The key against which the token be searched. + * @key The key against which the token be searched. * * @return If the token validated */ - public boolean function verify( - required string token = "", - string key - ){ + public boolean function verify( required string token = "", string key ){ var csrfData = cacheStorage.get( getTokenStorageKey(), {} ); // Mixins pass an empty key argument so "default" isn't set and verification fails when using the examples given in readme.md @@ -133,15 +130,7 @@ component accessors="true" singleton { var tokenBase = "#arguments.key##getRealIP()##randRange( 0, 65535, "SHA1PRNG" )##getTickCount()#"; // Return a 40 character hash as the new token - return uCase( - left( - hash( - tokenBase & variables.cacheStorage.getSessionKey(), - "SHA-256" - ), - 40 - ) - ); + return uCase( left( hash( tokenBase & variables.cacheStorage.getSessionKey(), "SHA-256" ), 40 ) ); } /** diff --git a/readme.md b/readme.md index f125a7c..9f22483 100644 --- a/readme.md +++ b/readme.md @@ -1,10 +1,25 @@ -[![Build Status](https://travis-ci.org/coldbox-modules/cbcsrf.svg?branch=master)](https://travis-ci.org/coldbox-modules/cbcsrf) +

+ +
+ + + +

+ +

+ Copyright Since 2005 ColdBox Platform by Luis Majano and Ortus Solutions, Corp +
+ www.coldbox.org | + www.ortussolutions.com +

+ +---- # ColdBox Anti Cross Site Request Forgery Module (cbcsrf) -A module that protects you against [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) attacks by generating unique FORM/client tokens and providing your ColdBox application with new functions for verifying these tokens. +A module that protects you against [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) attacks by generating unique FORM/client tokens and providing your ColdBox application with new functions for verifying these tokens. -Even though every CFML engine offers these functions natively, we have expanded them and have made them more flexible and more secure than the native CFML functions. +Even though every engine offers these functions natively, we have expanded them and have made them more flexible and more secure than the native functions. ## Features @@ -32,8 +47,9 @@ Apache License, Version 2.0. ## Requirements +* BoxLang 1+ * Lucee 5+ -* ColdFusion 2016+ +* ColdFusion 2021+ ## Installation @@ -199,7 +215,7 @@ The verification process is as follows: * If the incoming HTTP Method is a `get,options or head` skip verification * If the incoming event matches any of the `verifyExcludes` setting, then skip verification * If the action is marked with a `skipCsrf` annotation, then skip verification -* If no `rc.csrf` exists and no `x-csrf-token` header exists, throw a +* If no `rc.csrf` exists and no `x-csrf-token` header exists, throw a `TokenNotFoundException` exception * If the token is invalid then throw a `TokenMismatchException` exception @@ -234,7 +250,7 @@ component{ This module also allows you to turn on the generation HTTP endpoint via the `enableEndpoint` boolean setting. When turned on the module will register the following route: `GET /cbcsrf/generate/:key?`. You can use this endpoint to generate tokens for your users via AJAX or UI only applications. Please note that you can pass an optional `/:key` URL parameter that will generate the token for that specific key. -This endpoint should be secured, so we have annotated it with a `secured` annotation so if you are using `cbSecurity` or `cbGuard` this endpoint will only be available to logged in users. +This endpoint should be secured, so we have annotated it with a `secured` annotation so if you are using `cbSecurity` or `cbGuard` this endpoint will only be available to logged in users. ******************************************************************************** Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp @@ -249,7 +265,7 @@ Because of His grace, this project exists. If you don't like this, then don't re By whom also we have access by faith into this grace wherein we stand, and rejoice in hope of the glory of God. And not only so, but we glory in tribulations also: knowing that tribulation worketh patience; And patience, experience; and experience, hope: -And hope maketh not ashamed; because the love of God is shed abroad in our hearts by the +And hope maketh not ashamed; because the love of God is shed abroad in our hearts by the Holy Ghost which is given unto us. ." Romans 5:5 ### THE DAILY BREAD diff --git a/server-adobe@2021.json b/server-adobe@2021.json index 2f2410a..77f7931 100644 --- a/server-adobe@2021.json +++ b/server-adobe@2021.json @@ -17,7 +17,8 @@ } }, "jvm":{ - "heapSize":"1024" + "heapSize":"1024", + "javaVersion":"openjdk11_jre" }, "openBrowser":"false", "cfconfig":{ diff --git a/server-adobe@2023.json b/server-adobe@2023.json new file mode 100644 index 0000000..64af56a --- /dev/null +++ b/server-adobe@2023.json @@ -0,0 +1,29 @@ +{ + "name":"cbcsrf-adobe@2023", + "app":{ + "serverHomeDirectory":".engine/adobe2023", + "cfengine":"adobe@2023" + }, + "web":{ + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot": "test-harness", + "aliases":{ + "/moduleroot/cbcsrf":"../" + } + }, + "jvm":{ + "heapSize":"1024" + }, + "openBrowser":"false", + "cfconfig": { + "file" : ".cfconfig.json" + }, + "scripts" : { + "onServerInstall":"cfpm install zip,debugger,mysql" + } +} diff --git a/server-boxlang-cfml@1.json b/server-boxlang-cfml@1.json new file mode 100644 index 0000000..482e6fe --- /dev/null +++ b/server-boxlang-cfml@1.json @@ -0,0 +1,33 @@ +{ + "name":"cbcsrf-boxlang@1", + "app":{ + "serverHomeDirectory":".engine/boxlang", + "cfengine":"boxlang@be" + }, + "web":{ + "http":{ + "port":"60299" + }, + "rewrites":{ + "enable":"true" + }, + "webroot": "test-harness", + "aliases":{ + "/moduleroot/cbcsrf":"../" + } + }, + "JVM":{ + "heapSize":"1024", + "javaVersion":"openjdk21_jre", + "args":"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8888" + }, + "openBrowser":"false", + "cfconfig":{ + "file":".cfconfig.json" + }, + "env":{ + }, + "scripts":{ + "onServerInitialInstall":"install bx-compat-cfml --noSave" + } +} diff --git a/server-adobe@2018.json b/server-lucee@6.json similarity index 77% rename from server-adobe@2018.json rename to server-lucee@6.json index 435c0d1..27ac8ac 100644 --- a/server-adobe@2018.json +++ b/server-lucee@6.json @@ -1,8 +1,8 @@ { - "name":"cbcsrf-adobe@2018", + "name":"cbcsrf-lucee@6", "app":{ - "serverHomeDirectory":".engine/adobe2018", - "cfengine":"adobe@2018" + "serverHomeDirectory":".engine/lucee6", + "cfengine":"lucee@6" }, "web":{ "http":{ diff --git a/test-harness/box.json b/test-harness/box.json index a269a2f..0106138 100644 --- a/test-harness/box.json +++ b/test-harness/box.json @@ -7,7 +7,7 @@ "dependencies":{ "coldbox":"^6.0.0", "testbox":"*", - "cbstorages":"^2.0.0" + "cbstorages":"^3.0.0" }, "devDependencies":{}, "installPaths":{ @@ -23,4 +23,4 @@ "cfpm:install":"echo '\".engine/adobe2021/WEB-INF/cfusion/bin/cfpm.sh\" install ${1}' | run", "install:2021":"run-script cfpm:install zip" } -} \ No newline at end of file +} diff --git a/test-harness/tests/Application.cfc b/test-harness/tests/Application.cfc index e9d01c9..ccf0069 100644 --- a/test-harness/tests/Application.cfc +++ b/test-harness/tests/Application.cfc @@ -52,7 +52,7 @@ component { // If hitting the runner or specs, prep our virtual app if ( getBaseTemplatePath().replace( expandPath( "/tests" ), "" ).reFindNoCase( "(runner|specs)" ) ) { - request.coldBoxVirtualApp.startup(); + request.coldBoxVirtualApp.startup( true ); } return true; diff --git a/test-harness/tests/specs/csrfSpec.cfc b/test-harness/tests/specs/csrfSpec.cfc index 0105772..f0ee57b 100644 --- a/test-harness/tests/specs/csrfSpec.cfc +++ b/test-harness/tests/specs/csrfSpec.cfc @@ -1,27 +1,26 @@ /** -* My BDD Test -*/ -component extends="coldbox.system.testing.BaseTestCase" appMapping="/root"{ + * My BDD Test + */ +component extends="coldbox.system.testing.BaseTestCase" appMapping="/root" { function run(){ // all your suites go here. describe( "CSRF Module", function(){ - - beforeEach(function( currentSpec ){ - csrf = getInstance( "@cbcsrf" ); + beforeEach( function( currentSpec ){ + csrf = getInstance( "@cbcsrf" ); cacheStorage = getInstance( "cacheStorage@cbcsrf" ); csrf.rotate(); setup(); - }); + } ); it( "should register components", function(){ - expect( csrf ).toBeComponent(); - }); + expect( csrf ).toBeComponent(); + } ); it( "should run all integration points", function(){ - var event = execute( event="main.index", renderResults=true ); + var event = execute( event = "main.index", renderResults = true ); expect( event.getValue( "cbox_rendered_content" ) ).toMatch( "Verified: true" ); - }); + } ); it( "can generate and verify different tokens for different keys", function(){ var token1 = csrf.generate(); @@ -30,9 +29,8 @@ component extends="coldbox.system.testing.BaseTestCase" appMapping="/root"{ expect( token1 ).notToBe( token2 ); expect( csrf.verify( token1 ) ).toBeTrue(); expect( csrf.verify( token2, "unitTest" ) ).toBeTrue(); - }); - - }); + } ); + } ); } } diff --git a/test-harness/tests/specs/csrfVerifierSpec.cfc b/test-harness/tests/specs/csrfVerifierSpec.cfc index 5374241..d081777 100644 --- a/test-harness/tests/specs/csrfVerifierSpec.cfc +++ b/test-harness/tests/specs/csrfVerifierSpec.cfc @@ -1,70 +1,77 @@ /** -* My BDD Test -*/ -component extends="coldbox.system.testing.BaseTestCase" appMapping="/root"{ + * My BDD Test + */ +component extends="coldbox.system.testing.BaseTestCase" appMapping="/root" { function run(){ // all your suites go here. describe( "Verify Interceptor", function(){ - - beforeEach(function( currentSpec ){ + beforeEach( function( currentSpec ){ setup(); - csrf = getInstance( "@cbcsrf" ); - event = prepareMock( getRequestContext() ); - verifier = prepareMock( getInstance( dsl="coldbox:interceptor:VerifyCsfr@cbcsrf" ) ); + csrf = getInstance( "@cbcsrf" ); + event = prepareMock( getRequestContext() ); + verifier = prepareMock( getInstance( dsl = "coldbox:interceptor:VerifyCsfr@cbcsrf" ) ); verifier.setIsTestMode( false ); - }); + } ); it( "should be loaded", function(){ expect( verifier ).toBeComponent(); - }); + } ); it( "should not verify if the method is in GET/OPTIONS/HEAD", function(){ - var logger = prepareMock( verifier.getLog() ) - .$( "canDebug", true ) - .$( "debug" ); - event - .$( "getHTTPMethod", "OPTIONS" ) - .$( "getCurrentEvent", "hello.save" ); - verifier.preProcess( event, {}, event.getCollection(), event.getPrivateCollection() ); + var logger = prepareMock( verifier.getLog() ).$( "canDebug", true ).$( "debug" ); + event.$( "getHTTPMethod", "OPTIONS" ).$( "getCurrentEvent", "hello.save" ); + verifier.preProcess( + event, + {}, + event.getCollection(), + event.getPrivateCollection() + ); expect( logger.$callLog().debug[ 1 ][ 1 ] ).toInclude( "cbcsrf Verify skipped due to HTTP method" ); } ); it( "should not verify if the method is in the excludes list", function(){ - var logger = prepareMock( verifier.getLog() ) - .$( "canDebug", true ) - .$( "debug" ); - event - .$( "getHTTPMethod", "POST" ) - .$( "getCurrentEvent", "cbtest.index" ); - - verifier.preProcess( event, {}, event.getCollection(), event.getPrivateCollection() ); + var logger = prepareMock( verifier.getLog() ).$( "canDebug", true ).$( "debug" ); + event.$( "getHTTPMethod", "POST" ).$( "getCurrentEvent", "cbtest.index" ); + + verifier.preProcess( + event, + {}, + event.getCollection(), + event.getPrivateCollection() + ); expect( logger.$callLog().debug[ 1 ][ 1 ] ).toInclude( "cbcsrf Verify skipped as event:" ); } ); it( "should not verify if the action is marked for skipping", function(){ - var logger = prepareMock( verifier.getLog() ) - .$( "canDebug", true ) - .$( "debug" ); - event - .$( "getHTTPMethod", "POST" ) - .$( "getCurrentEvent", "verify.index" ); + var logger = prepareMock( verifier.getLog() ).$( "canDebug", true ).$( "debug" ); + event.$( "getHTTPMethod", "POST" ).$( "getCurrentEvent", "verify.index" ); verifier.$( "actionMarkedToSkip", true ); - verifier.preProcess( event, {}, event.getCollection(), event.getPrivateCollection() ); - expect( logger.$callLog().debug[ 1 ][ 1 ] ).toInclude( "cbcsrf Verify skipped as action has been annotated to skip" ); + verifier.preProcess( + event, + {}, + event.getCollection(), + event.getPrivateCollection() + ); + expect( logger.$callLog().debug[ 1 ][ 1 ] ).toInclude( + "cbcsrf Verify skipped as action has been annotated to skip" + ); } ); it( "should throw an exception if the token is not passed", function(){ - event - .$( "getHTTPMethod", "POST" ) - .$( "getCurrentEvent", "verify.index" ); + event.$( "getHTTPMethod", "POST" ).$( "getCurrentEvent", "verify.index" ); verifier.$( "actionMarkedToSkip", false ); expect( function(){ - verifier.preProcess( event, {}, event.getCollection(), event.getPrivateCollection() ); + verifier.preProcess( + event, + {}, + event.getCollection(), + event.getPrivateCollection() + ); } ).toThrow( "TokenNotFoundException" ); - }); + } ); it( "should invalidate if the token is invalid via the rc", function(){ event @@ -74,51 +81,70 @@ component extends="coldbox.system.testing.BaseTestCase" appMapping="/root"{ verifier.$( "actionMarkedToSkip", false ); expect( function(){ - verifier.preProcess( event, {}, event.getCollection(), event.getPrivateCollection() ); + verifier.preProcess( + event, + {}, + event.getCollection(), + event.getPrivateCollection() + ); } ).toThrow( "TokenMismatchException" ); - }); + } ); it( "should invalidate if the token is invalid via the header", function(){ event .$( "getHTTPMethod", "POST" ) .$( "getCurrentEvent", "verify.index" ) - .$( "getHttpHeader" ).$args( "x-csrf-token", "" ).$results( "456" ); + .$( "getHttpHeader" ) + .$args( "x-csrf-token", "" ) + .$results( "456" ); verifier.$( "actionMarkedToSkip", false ); expect( function(){ - verifier.preProcess( event, {}, event.getCollection(), event.getPrivateCollection() ); + verifier.preProcess( + event, + {}, + event.getCollection(), + event.getPrivateCollection() + ); } ).toThrow( "TokenMismatchException" ); - }); + } ); it( "should validate if the token is valid via the rc", function(){ - var logger = prepareMock( verifier.getLog() ) - .$( "canDebug", true ) - .$( "debug" ); + var logger = prepareMock( verifier.getLog() ).$( "canDebug", true ).$( "debug" ); event .$( "getHTTPMethod", "POST" ) .$( "getCurrentEvent", "verify.index" ) .setValue( "csrf", csrf.generate() ); verifier.$( "actionMarkedToSkip", false ); - verifier.preProcess( event, {}, event.getCollection(), event.getPrivateCollection() ); + verifier.preProcess( + event, + {}, + event.getCollection(), + event.getPrivateCollection() + ); expect( logger.$callLog().debug[ 1 ][ 1 ] ).toInclude( "cbcsrf verified for" ); - }); + } ); it( "should validate if the token is valid via the header", function(){ - var logger = prepareMock( verifier.getLog() ) - .$( "canDebug", true ) - .$( "debug" ); + var logger = prepareMock( verifier.getLog() ).$( "canDebug", true ).$( "debug" ); event .$( "getHTTPMethod", "POST" ) .$( "getCurrentEvent", "verify.index" ) - .$( "getHttpHeader" ).$args( "x-csrf-token", "" ).$results( csrf.generate() ); + .$( "getHttpHeader" ) + .$args( "x-csrf-token", "" ) + .$results( csrf.generate() ); verifier.$( "actionMarkedToSkip", false ); - verifier.preProcess( event, {}, event.getCollection(), event.getPrivateCollection() ); + verifier.preProcess( + event, + {}, + event.getCollection(), + event.getPrivateCollection() + ); expect( logger.$callLog().debug[ 1 ][ 1 ] ).toInclude( "cbcsrf verified for" ); - }); - - }); + } ); + } ); } -} \ No newline at end of file +}