diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 3b4b7ae9..00000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,12 +0,0 @@ - - -### Actual behavior - -### Expected behavior - -### Steps to reproduce the behavior - - - - diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 680ec362..90c15174 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -3,9 +3,6 @@ contact_links: - name: Help / Questions url: https://github.com/Requarks/wiki/discussions/categories/help-questions about: Ask the community for help on using or setting up Wiki.js - - name: Report a Security Issue - url: https://github.com/Requarks/wiki/security/policy - about: Privately report security issues so they can be addressed quickly. - name: Errors / Bug Reports url: https://github.com/Requarks/wiki/discussions/categories/error-bug-report about: Create a discussion around the bug / error you're getting. If validated, a proper GitHub issue will be created so that it can be worked on. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 304f20e4..6bc8b479 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: packages: write steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Set Build Variables run: | @@ -42,20 +42,22 @@ jobs: cat package.json - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker images - uses: docker/build-push-action@v2.9.0 + uses: docker/build-push-action@v7 + env: + DOCKER_BUILD_SUMMARY: false with: context: . file: dev/build/Dockerfile @@ -77,7 +79,7 @@ jobs: find _dist/wiki/ -printf "%P\n" | tar -czf wiki-js.tar.gz --no-recursion -C _dist/wiki/ -T - - name: Upload a Build Artifact - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v7 with: name: drop path: wiki-js.tar.gz @@ -89,10 +91,10 @@ jobs: strategy: matrix: - dbtype: [postgres, mysql, mariadb, mssql, sqlite] + dbtype: [postgres, mysql, mariadb, sqlite] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Set Test Variables run: | @@ -115,21 +117,13 @@ jobs: arm: name: ARM Build - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm needs: [cypress] permissions: packages: write - strategy: - matrix: - include: - - platform: linux/arm64 - docker: arm64 - - platform: linux/arm/v7 - docker: armv7 - steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Set Version Variables run: | @@ -142,26 +136,26 @@ jobs: fi - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v4 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Download a Build Artifact - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v8 with: name: drop path: drop @@ -172,15 +166,18 @@ jobs: tar -xzf $GITHUB_WORKSPACE/drop/wiki-js.tar.gz -C $GITHUB_WORKSPACE/build --exclude=node_modules - name: Build and push Docker images - uses: docker/build-push-action@v2.9.0 + uses: docker/build-push-action@v7 + env: + DOCKER_BUILD_SUMMARY: false with: context: . file: dev/build-arm/Dockerfile - platforms: ${{ matrix.platform }} + platforms: linux/arm64 + provenance: false push: true tags: | - requarks/wiki:canary-${{ matrix.docker }}-${{ env.REL_VERSION_STRICT }} - ghcr.io/requarks/wiki:canary-${{ matrix.docker }}-${{ env.REL_VERSION_STRICT }} + requarks/wiki:canary-arm64-${{ env.REL_VERSION_STRICT }} + ghcr.io/requarks/wiki:canary-arm64-${{ env.REL_VERSION_STRICT }} windows: name: Windows Build @@ -189,12 +186,12 @@ jobs: steps: - name: Setup Node.js environment - uses: actions/setup-node@v2.5.1 + uses: actions/setup-node@v6 with: - node-version: 16.x + node-version: 24.x - name: Download a Build Artifact - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v8 with: name: drop path: drop @@ -202,17 +199,25 @@ jobs: - name: Extract Build run: | mkdir -p win - tar -xzf $env:GITHUB_WORKSPACE\drop\wiki-js.tar.gz -C $env:GITHUB_WORKSPACE\win --exclude=node_modules + tar -xzf $env:GITHUB_WORKSPACE\drop\wiki-js.tar.gz -C $env:GITHUB_WORKSPACE\win + Copy-Item win\node_modules\extract-files\package.json patch-extractfile.json -Force + Remove-Item -Path win\node_modules -Force -Recurse - name: Install Dependencies - run: yarn --production --frozen-lockfile --non-interactive + run: | + yarn --production --frozen-lockfile --non-interactive + yarn patch-package working-directory: win + - name: Fix patched packages + run: | + Copy-Item patch-extractfile.json win\node_modules\extract-files\package.json -Force + - name: Create Bundle - run: tar -czf wiki-js-windows.tar.gz -C $env:GITHUB_WORKSPACE\win . + run: tar -czf $env:GITHUB_WORKSPACE\wiki-js-windows.tar.gz -C $env:GITHUB_WORKSPACE\win . - name: Upload a Build Artifact - uses: actions/upload-artifact@v2.3.1 + uses: actions/upload-artifact@v7 with: name: drop-win path: wiki-js-windows.tar.gz @@ -232,13 +237,13 @@ jobs: echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -248,8 +253,8 @@ jobs: run: | echo "Creating the manifests..." - docker manifest create requarks/wiki:beta-$REL_VERSION_STRICT requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT requarks/wiki:canary-armv7-$REL_VERSION_STRICT - docker manifest create ghcr.io/requarks/wiki:beta-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-armv7-$REL_VERSION_STRICT + docker manifest create requarks/wiki:beta-$REL_VERSION_STRICT requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT + docker manifest create ghcr.io/requarks/wiki:beta-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT echo "Pushing the manifests..." @@ -273,13 +278,13 @@ jobs: echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -298,14 +303,14 @@ jobs: echo "Using major $MAJOR and minor $MINOR..." echo "Creating the manifests..." - docker manifest create requarks/wiki:$REL_VERSION_STRICT requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT requarks/wiki:canary-armv7-$REL_VERSION_STRICT - docker manifest create requarks/wiki:$MAJOR requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT requarks/wiki:canary-armv7-$REL_VERSION_STRICT - docker manifest create requarks/wiki:$MAJORMINOR requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT requarks/wiki:canary-armv7-$REL_VERSION_STRICT - docker manifest create requarks/wiki:latest requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT requarks/wiki:canary-armv7-$REL_VERSION_STRICT - docker manifest create ghcr.io/requarks/wiki:$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-armv7-$REL_VERSION_STRICT - docker manifest create ghcr.io/requarks/wiki:$MAJOR ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-armv7-$REL_VERSION_STRICT - docker manifest create ghcr.io/requarks/wiki:$MAJORMINOR ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-armv7-$REL_VERSION_STRICT - docker manifest create ghcr.io/requarks/wiki:latest ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-armv7-$REL_VERSION_STRICT + docker manifest create requarks/wiki:$REL_VERSION_STRICT requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT + docker manifest create requarks/wiki:$MAJOR requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT + docker manifest create requarks/wiki:$MAJORMINOR requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT + docker manifest create requarks/wiki:latest requarks/wiki:canary-$REL_VERSION_STRICT requarks/wiki:canary-arm64-$REL_VERSION_STRICT + docker manifest create ghcr.io/requarks/wiki:$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT + docker manifest create ghcr.io/requarks/wiki:$MAJOR ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT + docker manifest create ghcr.io/requarks/wiki:$MAJORMINOR ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT + docker manifest create ghcr.io/requarks/wiki:latest ghcr.io/requarks/wiki:canary-$REL_VERSION_STRICT ghcr.io/requarks/wiki:canary-arm64-$REL_VERSION_STRICT echo "Pushing the manifests..." @@ -319,13 +324,13 @@ jobs: docker manifest push -p ghcr.io/requarks/wiki:latest - name: Download Linux Build - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v8 with: name: drop path: drop - name: Download Windows Build - uses: actions/download-artifact@v2.1.0 + uses: actions/download-artifact@v8 with: name: drop-win path: drop-win @@ -339,28 +344,29 @@ jobs: writeToFile: false - name: Update GitHub Release - uses: ncipollo/release-action@v1 + uses: ncipollo/release-action@v1.21.0 with: allowUpdates: true draft: false + makeLatest: true name: ${{ github.ref_name }} body: ${{ steps.changelog.outputs.changes }} token: ${{ github.token }} artifacts: 'drop/wiki-js.tar.gz,drop-win/wiki-js-windows.tar.gz' - - name: Notify Slack Releases Channel - uses: slackapi/slack-github-action@v1.18.0 - with: - payload: | - { - "text": "Wiki.js ${{ github.ref_name }} has been released." - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK + # - name: Notify Slack Releases Channel + # uses: slackapi/slack-github-action@v1.26.0 + # with: + # payload: | + # { + # "text": "Wiki.js ${{ github.ref_name }} has been released." + # } + # env: + # SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + # SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK - name: Notify Telegram Channel - uses: appleboy/telegram-action@v0.1.1 + uses: appleboy/telegram-action@v1.0.1 with: to: ${{ secrets.TELEGRAM_TO }} token: ${{ secrets.TELEGRAM_TOKEN }} @@ -371,34 +377,34 @@ jobs: See [release notes](https://github.com/requarks/wiki/releases) for details. - name: Notify Discord Channel - uses: sebastianpopp/discord-action@v1.0 + uses: sebastianpopp/discord-action@v2.0 with: webhook: ${{ secrets.DISCORD_WEBHOOK }} message: Wiki.js ${{ github.ref_name }} has been released! See https://github.com/requarks/wiki/releases for details. - build-do-image: - name: Build DigitalOcean Image - runs-on: ubuntu-latest - needs: [release] - - steps: - - uses: actions/checkout@v2 - - - name: Set Version Variables - run: | - echo "Using TAG mode: $GITHUB_REF_NAME" - echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV - - - name: Install Packer - run: | - curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - - sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" - sudo apt-get update && sudo apt-get install packer - - - name: Build Droplet Image - env: - DIGITALOCEAN_API_TOKEN: ${{ secrets.DO_TOKEN }} - WIKI_APP_VERSION: ${{ env.REL_VERSION_STRICT }} - working-directory: dev/packer - run: | - packer build digitalocean.json + # build-do-image: + # name: Build DigitalOcean Image + # runs-on: ubuntu-latest + # needs: [release] + + # steps: + # - uses: actions/checkout@v6 + + # - name: Set Version Variables + # run: | + # echo "Using TAG mode: $GITHUB_REF_NAME" + # echo "REL_VERSION_STRICT=${GITHUB_REF_NAME#?}" >> $GITHUB_ENV + + # - name: Install Packer + # run: | + # curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - + # sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" + # sudo apt-get update && sudo apt-get install packer + + # - name: Build Droplet Image + # env: + # DIGITALOCEAN_API_TOKEN: ${{ secrets.DO_TOKEN }} + # WIKI_APP_VERSION: ${{ env.REL_VERSION_STRICT }} + # working-directory: dev/packer + # run: | + # packer build digitalocean.json diff --git a/.github/workflows/helm.yml b/.github/workflows/helm.yml index 5c27af1e..9543c076 100644 --- a/.github/workflows/helm.yml +++ b/.github/workflows/helm.yml @@ -16,11 +16,12 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Package and Push Chart run: | + export CHARTVER=$(yq '.version' dev/helm/Chart.yaml) helm plugin install https://github.com/chartmuseum/helm-push.git helm repo add chartmuseum https://charts.js.wiki - helm cm-push --version="2.2.${{github.run_number}}" --username="${{secrets.HELM_REPO_USERNAME}}" --password="${{secrets.HELM_REPO_PASSWORD}}" dev/helm/ chartmuseum + helm cm-push --version="$CHARTVER" --username="${{secrets.HELM_REPO_USERNAME}}" --password="${{secrets.HELM_REPO_PASSWORD}}" dev/helm/ chartmuseum helm repo remove chartmuseum diff --git a/.github/workflows/packer.yml b/.github/workflows/packer.yml index 4ef42f31..ed1c9495 100644 --- a/.github/workflows/packer.yml +++ b/.github/workflows/packer.yml @@ -14,13 +14,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v6 - name: Install Packer run: | - curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add - - sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main" - sudo apt-get update && sudo apt-get install packer + wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(grep -oP '(?<=UBUNTU_CODENAME=).*' /etc/os-release || lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list + sudo apt update && sudo apt install packer - name: Build Droplet Image env: @@ -28,4 +28,5 @@ jobs: WIKI_APP_VERSION: ${{ github.event.inputs.version }} working-directory: dev/packer run: | + packer plugins install github.com/digitalocean/digitalocean packer build digitalocean.json diff --git a/.nvmrc b/.nvmrc index 0c6886ca..821e3957 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v12.16.3 +v24.12.0 diff --git a/.vscode/settings.json b/.vscode/settings.json index dc1a054c..75e3a447 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,7 +8,7 @@ "vue" ], "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "i18n-ally.localesPaths": [ "server/locales" diff --git a/README.md b/README.md index bccf16fc..9b2b9f1c 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@
-Wiki.js + + + Wiki.js + [![Release](https://img.shields.io/github/release/Requarks/wiki.svg?style=flat&maxAge=3600)](https://github.com/Requarks/wiki/releases) [![License](https://img.shields.io/badge/license-AGPLv3-blue.svg?style=flat)](https://github.com/requarks/wiki/blob/master/LICENSE) [![Standard - JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-green.svg?style=flat&logo=javascript&logoColor=white)](http://standardjs.com/) -[![Downloads](https://img.shields.io/github/downloads/Requarks/wiki/total.svg?style=flat&logo=github)](https://github.com/Requarks/wiki/releases) -[![Docker Pulls](https://img.shields.io/docker/pulls/requarks/wiki.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/requarks/wiki/) -[![Build + Publish](https://github.com/Requarks/wiki/actions/workflows/build.yml/badge.svg)](https://github.com/Requarks/wiki/actions/workflows/build.yml) -[![Huntr](https://img.shields.io/badge/security%20bounty-disclose-brightgreen.svg?style=flat&logo=cachet&logoColor=white)](https://huntr.dev/bounties/disclose) +[![Build + Publish](https://github.com/Requarks/wiki/actions/workflows/build.yml/badge.svg)](https://github.com/Requarks/wiki/actions/workflows/build.yml) [![GitHub Sponsors](https://img.shields.io/github/sponsors/ngpixel?logo=github&color=ea4aaa)](https://github.com/users/NGPixel/sponsorship) [![Open Collective backers and sponsors](https://img.shields.io/opencollective/all/wikijs?label=backers&color=218bff&logo=opencollective&logoColor=white)](https://opencollective.com/wikijs) -[![Subscribe to Newsletter](https://img.shields.io/badge/newsletter-subscribe-yellow.svg?style=flat&logo=mailchimp&logoColor=white)](https://blog.js.wiki/subscribe) -[![Chat on Slack](https://img.shields.io/badge/slack-requarks-CC2B5E.svg?style=flat&logo=slack)](https://wiki.requarks.io/slack) -[![Follow on Twitter](https://img.shields.io/badge/twitter-%40requarks-blue.svg?style=flat&logo=twitter&logoColor=white)](https://twitter.com/requarks) -[![Follow on Telegram](https://img.shields.io/badge/telegram-%40wiki__js-blue.svg?style=flat&logo=telegram)](https://t.me/wiki_js) +[![Downloads](https://img.shields.io/github/downloads/Requarks/wiki/total.svg?style=flat&logo=github)](https://github.com/Requarks/wiki/releases) +[![Docker Pulls](https://img.shields.io/docker/pulls/requarks/wiki.svg?logo=docker&logoColor=white)](https://hub.docker.com/r/requarks/wiki/) [![Chat on Discord](https://img.shields.io/badge/discord-join-8D96F6.svg?style=flat&logo=discord&logoColor=white)](https://discord.gg/rcxt9QS2jd) +[![Follow on Bluesky](https://img.shields.io/badge/bluesky-%40js.wiki-blue.svg?style=flat&logo=bluesky&logoColor=white)](https://bsky.app/profile/js.wiki) +[![Follow on Telegram](https://img.shields.io/badge/telegram-%40wiki__js-blue.svg?style=flat&logo=telegram)](https://t.me/wiki_js) [![Reddit](https://img.shields.io/badge/reddit-%2Fr%2Fwikijs-orange?logo=reddit&logoColor=white)](https://www.reddit.com/r/wikijs/) ##### A modern, lightweight and powerful wiki app built on NodeJS @@ -29,9 +29,8 @@ - [Demo](https://docs.requarks.io/demo) - [Changelog](https://github.com/requarks/wiki/releases) - [Feature Requests](https://feedback.js.wiki/wiki) -- [Chat with us on Slack](https://wiki.requarks.io/slack) +- Chat with us on [Discord](https://discord.gg/rcxt9QS2jd) - [Translations](https://docs.requarks.io/dev/translations) *(We need your help!)* -- [E2E Testing Results](https://dashboard.cypress.io/projects/r7qxah/runs) - [Special Thanks](#special-thanks) - [Contribute](#contributors) @@ -82,11 +81,6 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - - - - - @@ -96,53 +90,74 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - + - - - + - + + + - - - - - - + +
+ + + + + Alexander Casassovici
(@alexksso)
+ Broxen
(@broxen)
+ Dacon
(@xDacon)
+ + + Maxime Pierre
(@DonNabla) +
+
+ + + + +
Jay Daley
(@JayDaley)
+ Oleksii
(@idokka)
+ + - - + + + Shane Kearney
(@shanekearney)
+ + + +
@@ -160,9 +175,11 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - Cloud Data Hosting LLC ([@CloudDataHostingLLC](https://github.com/CloudDataHostingLLC)) - Cole Manning ([@RVRX](https://github.com/RVRX)) - CrazyMarvin ([@CrazyMarvin](https://github.com/CrazyMarvin)) +- Daniel Horner ([@danhorner](https://github.com/danhorner)) - David Christian Holin ([@SirGibihm](https://github.com/SirGibihm)) - Dragan Espenschied ([@despens](https://github.com/despens)) - Elijah Zobenko ([@he110](https://github.com/he110)) +- Emerson-Perna ([@Emerson-Perna](https://github.com/Emerson-Perna)) - Ernie ([@iamernie](https://github.com/iamernie)) - Fabio Ferrari ([@devxops](https://github.com/devxops)) - Finsa S.p.A. ([@finsaspa](https://github.com/finsaspa)) @@ -178,33 +195,40 @@ Support this project by becoming a sponsor. Your name will show up in the Contri - MaFarine ([@MaFarine](https://github.com/MaFarine)) - Marcilio Leite Neto ([@marclneto](https://github.com/marclneto)) - Mattias Johnson ([@mattiasJohnson](https://github.com/mattiasJohnson)) - - - - - Max Ricketts-Uy ([@MaxRickettsUy](https://github.com/MaxRickettsUy)) - Mickael Asseline ([@PAPAMICA](https://github.com/PAPAMICA)) - Mitchell Rowton ([@mrowton](https://github.com/mrowton)) + + + + - M. Scott Ford ([@mscottford](https://github.com/mscottford)) - Nick Halase ([@nhalase](https://github.com/nhalase)) - Nick Price ([@DominoTree](https://github.com/DominoTree)) - Nina Reynolds ([@cutecycle](https://github.com/cutecycle)) - Noel Cower ([@nilium](https://github.com/nilium)) - Oleksandr Koltsov ([@crambo](https://github.com/crambo)) +- Phi Zeroth ([@phizeroth](https://github.com/phizeroth)) - Philipp Schmitt ([@pschmitt](https://github.com/pschmitt)) - Robert Lanzke ([@winkelement](https://github.com/winkelement)) - Ruizhe Li ([@liruizhe1995](https://github.com/liruizhe1995)) - Sam Martin ([@ABitMoreDepth](https://github.com/ABitMoreDepth)) - Sean Coffey ([@seanecoffey](https://github.com/seanecoffey)) +- Simon Ott ([@ottsimon](https://github.com/ottsimon)) - Stephan Kristyn ([@stevek-pro](https://github.com/stevek-pro)) - Theodore Chu ([@TheodoreChu](https://github.com/TheodoreChu)) +- Tim Elmer ([@tim-elmer](https://github.com/tim-elmer)) - Tyler Denman ([@tylerguy](https://github.com/tylerguy)) - Victor Bilgin ([@vbilgin](https://github.com/vbilgin)) - VMO Solutions ([@vmosolutions](https://github.com/vmosolutions)) +- YazMogg35 ([@YazMogg35](https://github.com/YazMogg35)) +- Yu Yongwoo ([@uyu423](https://github.com/uyu423)) - ameyrakheja ([@ameyrakheja](https://github.com/ameyrakheja)) - aniketpanjwani ([@aniketpanjwani](https://github.com/aniketpanjwani)) - aytaa ([@aytaa](https://github.com/aytaa)) +- cesar ([@cesarnr21](https://github.com/cesarnr21)) - chaee ([@chaee](https://github.com/chaee)) +- lwileczek ([@lwileczek](https://github.com/lwileczek)) - magicpotato ([@fortheday](https://github.com/fortheday)) - motoacs ([@motoacs](https://github.com/motoacs)) - muzian666 ([@muzian666](https://github.com/muzian666)) @@ -375,6 +399,23 @@ Support this project by becoming a sponsor. Your logo will show up in the Contri + + + + + + + + + + + + + + + + +
@@ -387,16 +428,21 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re
+- Aeternum - Al Romano - Alex Balabanov +- Alex Milanov - Alex Zen - Arti Zirk - Ave - Brandon Curtis +- Damien Hottelier +- Daniel T. Holtzclaw - Dave 'Sri' Seah - djagoo - dz - Douglas Lassance +- Ergoflix - Ernie Reid - Etienne - Flemis Jurgenheimer @@ -407,11 +453,11 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re - Ian - Imari Childress - Iskander Callos -- Josh Stewart +- Josh Stewart - Justin Dunsworth - Keir - Loïc CRAMPON @@ -420,14 +466,17 @@ Thank you to all our patrons! 🙏 [[Become a patron](https://www.patreon.com/re - Mads Rosendahl - Mark Mansur - Matt Gedigian +- Mike Ditton - Nate Figz - Patryk +- Paul O'Fallon - Philipp Schürch - Tracey Duffy - Quaxim - Richeir - Sergio Navarro Fernández - Shad Narcher +- ShadowVoyd - SmartNET.works - Stepan Sokolovskyi - Zach Crawford diff --git a/SECURITY.md b/SECURITY.md index 44cfc409..b905767f 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -13,15 +13,10 @@ If you find such vulnerability, it's important to disclose it in a quick and sec ## Reporting a Vulnerability -**DO NOT CREATE AN ISSUE ON GITHUB** to report a potential vulnerability / security problem. Instead, choose one of these options: +> [!CAUTION] +> **DO NOT CREATE A GITHUB ISSUE / DISCUSSION** to report a potential vulnerability / security problem. Instead, use the process below: -### A) Disclose on Huntr.dev - -Disclose the vulnerability on [Huntr.dev](https://huntr.dev/bounties/disclose) for the repository `https://github.com/Requarks/wiki`. - -### B) Send an email - -Send an email to security@requarks.io. +Submit a Vulnerability Report by filling in the form on https://github.com/requarks/wiki/security/advisories/new Include as much details as possible, such as: - The version(s) of Wiki.js that are impacted @@ -31,3 +26,6 @@ Include as much details as possible, such as: - Your GitHub username if you'd like to be included as a collaborator on the private fix branch The vulnerability will be investigated ASAP. If deemed valid, a draft security advisory will be created on GitHub and you will be included as a collaborator. A fix will be worked on in a private branch to resolves the issue. Once a fix is available, the advisory will be published. + +> [!NOTE] +> There's no reward for submitting a report. As this is open source project and not corporate owned, we are not able to provide monetary rewards. You will however be credited as the bug reporter in the release notes. diff --git a/client/client-app.js b/client/client-app.js index 40f4cc60..cdf27a80 100644 --- a/client/client-app.js +++ b/client/client-app.js @@ -103,7 +103,7 @@ const graphQLLink = ApolloLink.from([ // Handle renewed JWT const newJWT = resp.headers.get('new-jwt') if (newJWT) { - Cookies.set('jwt', newJWT, { expires: 365 }) + Cookies.set('jwt', newJWT, { expires: 365, secure: window.location.protocol === 'https:' }) } return resp } @@ -114,7 +114,11 @@ const graphQLWSLink = new WebSocketLink({ uri: graphQLWSEndpoint, options: { reconnect: true, - lazy: true + lazy: true, + connectionParams: () => { + const token = Cookies.get('jwt') + return token ? { token } : {} + } } }) @@ -148,30 +152,30 @@ Vue.prototype.Velocity = Velocity // Register Vue Components // ==================================== -Vue.component('admin', () => import(/* webpackChunkName: "admin" */ './components/admin.vue')) -Vue.component('comments', () => import(/* webpackChunkName: "comments" */ './components/comments.vue')) -Vue.component('editor', () => import(/* webpackPrefetch: -100, webpackChunkName: "editor" */ './components/editor.vue')) -Vue.component('history', () => import(/* webpackChunkName: "history" */ './components/history.vue')) -Vue.component('loader', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/loader.vue')) -Vue.component('login', () => import(/* webpackPrefetch: true, webpackChunkName: "login" */ './components/login.vue')) -Vue.component('nav-header', () => import(/* webpackMode: "eager" */ './components/common/nav-header.vue')) -Vue.component('new-page', () => import(/* webpackChunkName: "new-page" */ './components/new-page.vue')) -Vue.component('notify', () => import(/* webpackMode: "eager" */ './components/common/notify.vue')) -Vue.component('not-found', () => import(/* webpackChunkName: "not-found" */ './components/not-found.vue')) -Vue.component('page-selector', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/page-selector.vue')) -Vue.component('page-source', () => import(/* webpackChunkName: "source" */ './components/source.vue')) -Vue.component('profile', () => import(/* webpackChunkName: "profile" */ './components/profile.vue')) -Vue.component('register', () => import(/* webpackChunkName: "register" */ './components/register.vue')) -Vue.component('search-results', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/search-results.vue')) -Vue.component('social-sharing', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/social-sharing.vue')) -Vue.component('tags', () => import(/* webpackChunkName: "tags" */ './components/tags.vue')) -Vue.component('unauthorized', () => import(/* webpackChunkName: "unauthorized" */ './components/unauthorized.vue')) -Vue.component('v-card-chin', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/v-card-chin.vue')) -Vue.component('v-card-info', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/v-card-info.vue')) -Vue.component('welcome', () => import(/* webpackChunkName: "welcome" */ './components/welcome.vue')) - -Vue.component('nav-footer', () => import(/* webpackChunkName: "theme" */ './themes/' + siteConfig.theme + '/components/nav-footer.vue')) -Vue.component('page', () => import(/* webpackChunkName: "theme" */ './themes/' + siteConfig.theme + '/components/page.vue')) +Vue.component('Admin', () => import(/* webpackChunkName: "admin" */ './components/admin.vue')) +Vue.component('Comments', () => import(/* webpackChunkName: "comments" */ './components/comments.vue')) +Vue.component('Editor', () => import(/* webpackPrefetch: -100, webpackChunkName: "editor" */ './components/editor.vue')) +Vue.component('History', () => import(/* webpackChunkName: "history" */ './components/history.vue')) +Vue.component('Loader', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/loader.vue')) +Vue.component('Login', () => import(/* webpackPrefetch: true, webpackChunkName: "login" */ './components/login.vue')) +Vue.component('NavHeader', () => import(/* webpackMode: "eager" */ './components/common/nav-header.vue')) +Vue.component('NewPage', () => import(/* webpackChunkName: "new-page" */ './components/new-page.vue')) +Vue.component('Notify', () => import(/* webpackMode: "eager" */ './components/common/notify.vue')) +Vue.component('NotFound', () => import(/* webpackChunkName: "not-found" */ './components/not-found.vue')) +Vue.component('PageSelector', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/page-selector.vue')) +Vue.component('PageSource', () => import(/* webpackChunkName: "source" */ './components/source.vue')) +Vue.component('Profile', () => import(/* webpackChunkName: "profile" */ './components/profile.vue')) +Vue.component('Register', () => import(/* webpackChunkName: "register" */ './components/register.vue')) +Vue.component('SearchResults', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/search-results.vue')) +Vue.component('SocialSharing', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/social-sharing.vue')) +Vue.component('Tags', () => import(/* webpackChunkName: "tags" */ './components/tags.vue')) +Vue.component('Unauthorized', () => import(/* webpackChunkName: "unauthorized" */ './components/unauthorized.vue')) +Vue.component('VCardChin', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/v-card-chin.vue')) +Vue.component('VCardInfo', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/v-card-info.vue')) +Vue.component('Welcome', () => import(/* webpackChunkName: "welcome" */ './components/welcome.vue')) + +Vue.component('NavFooter', () => import(/* webpackChunkName: "theme" */ './themes/' + siteConfig.theme + '/components/nav-footer.vue')) +Vue.component('Page', () => import(/* webpackChunkName: "theme" */ './themes/' + siteConfig.theme + '/components/page.vue')) let bootstrap = () => { // ==================================== diff --git a/client/components/admin/admin-general.vue b/client/components/admin/admin-general.vue index 8804ee39..07596074 100644 --- a/client/components/admin/admin-general.vue +++ b/client/components/admin/admin-general.vue @@ -82,6 +82,15 @@ :return-object='false' :hint='$t(`admin:general.contentLicenseHint`)' persistent-hint + ) + v-text-field.mt-3( + outlined + :label='$t(`admin:general.footerOverride`)' + v-model='config.footerOverride' + prepend-icon='mdi-page-layout-footer' + append-icon='mdi-language-markdown' + persistent-hint + :hint='$t(`admin:general.footerOverrideHint`)' ) v-divider .overline.grey--text.pa-4 SEO @@ -280,6 +289,7 @@ export default { analyticsId: '', company: '', contentLicense: '', + footerOverride: '', logoUrl: '', featureAnalytics: false, featurePageRatings: false, @@ -308,6 +318,7 @@ export default { logoUrl: sync('site/logoUrl'), company: sync('site/company'), contentLicense: sync('site/contentLicense'), + footerOverride: sync('site/footerOverride'), activeModal: sync('editor/activeModal'), contentLicenses () { return [ @@ -346,6 +357,7 @@ export default { $analyticsId: String $company: String $contentLicense: String + $footerOverride: String $logoUrl: String $pageExtensions: String $featurePageRatings: Boolean @@ -369,6 +381,7 @@ export default { analyticsId: $analyticsId company: $company contentLicense: $contentLicense + footerOverride: $footerOverride logoUrl: $logoUrl pageExtensions: $pageExtensions featurePageRatings: $featurePageRatings @@ -401,6 +414,7 @@ export default { analyticsId: _.get(this.config, 'analyticsId', ''), company: _.get(this.config, 'company', ''), contentLicense: _.get(this.config, 'contentLicense', ''), + footerOverride: _.get(this.config, 'footerOverride', ''), logoUrl: _.get(this.config, 'logoUrl', ''), pageExtensions: _.get(this.config, 'pageExtensions', ''), featurePageRatings: _.get(this.config, 'featurePageRatings', false), @@ -426,6 +440,7 @@ export default { this.siteTitle = this.config.title this.company = this.config.company this.contentLicense = this.config.contentLicense + this.footerOverride = this.config.footerOverride this.logoUrl = this.config.logoUrl } catch (err) { this.$store.commit('pushGraphError', err) @@ -461,6 +476,7 @@ export default { analyticsId company contentLicense + footerOverride logoUrl pageExtensions featurePageRatings diff --git a/client/components/admin/admin-groups-edit-permissions.vue b/client/components/admin/admin-groups-edit-permissions.vue index 91b1b684..62304129 100644 --- a/client/components/admin/admin-groups-edit-permissions.vue +++ b/client/components/admin/admin-groups-edit-permissions.vue @@ -149,28 +149,28 @@ export default { items: [ { permission: 'write:users', - hint: 'Can create or authorize new users, but not modify existing ones', + hint: 'Can create or authorize new users, but not modify existing ones. Can only assign to non-administrative groups', warning: false, restrictedForSystem: true, disabled: false }, { permission: 'manage:users', - hint: 'Can manage all users (but not users with administrative permissions)', + hint: 'Can create, authorize and modify ANY users. Can only assign to non-administrative groups', warning: false, restrictedForSystem: true, disabled: false }, { permission: 'write:groups', - hint: 'Can manage groups and assign CONTENT permissions / page rules', + hint: 'Can manage groups and set CONTENT permissions / page rules. Can only assign users to non-administrative groups', warning: false, restrictedForSystem: true, disabled: false }, { permission: 'manage:groups', - hint: 'Can manage groups and assign ANY permissions (but not manage:system) / page rules', + hint: 'Can manage groups and set ANY permissions (but not manage:system) / page rules. Can assign users to ANY groups (except groups with the manage:system permission)', warning: true, restrictedForSystem: true, disabled: false @@ -203,7 +203,7 @@ export default { }, { permission: 'manage:system', - hint: 'Can manage and access everything. Root administrator.', + hint: 'Can manage and access everything. Root administrator', warning: true, restrictedForSystem: true, disabled: true diff --git a/client/components/admin/admin-pages-edit.vue b/client/components/admin/admin-pages-edit.vue index cd43533b..aef5126c 100644 --- a/client/components/admin/admin-pages-edit.vue +++ b/client/components/admin/admin-pages-edit.vue @@ -39,14 +39,14 @@ v-list-item-icon v-icon(color='indigo') mdi-pencil v-list-item-title Edit - v-list-item(@click='', disabled) - v-list-item-icon - v-icon(color='grey') mdi-cube-scan - v-list-item-title Re-Render - v-list-item(@click='', disabled) - v-list-item-icon - v-icon(color='grey') mdi-earth-remove - v-list-item-title Unpublish + //- v-list-item(@click='', disabled) + //- v-list-item-icon + //- v-icon(color='grey') mdi-cube-scan + //- v-list-item-title Re-Render + //- v-list-item(@click='', disabled) + //- v-list-item-icon + //- v-icon(color='grey') mdi-earth-remove + //- v-list-item-title Unpublish v-list-item(:href='`/s/` + page.locale + `/` + page.path') v-list-item-icon v-icon(color='indigo') mdi-code-tags @@ -55,14 +55,14 @@ v-list-item-icon v-icon(color='indigo') mdi-history v-list-item-title View History - v-list-item(@click='', disabled) - v-list-item-icon - v-icon(color='grey') mdi-content-duplicate - v-list-item-title Duplicate - v-list-item(@click='', disabled) - v-list-item-icon - v-icon(color='grey') mdi-content-save-move-outline - v-list-item-title Move / Rename + //- v-list-item(@click='', disabled) + //- v-list-item-icon + //- v-icon(color='grey') mdi-content-duplicate + //- v-list-item-title Duplicate + //- v-list-item(@click='', disabled) + //- v-list-item-icon + //- v-icon(color='grey') mdi-content-save-move-outline + //- v-list-item-title Move / Rename v-dialog(v-model='deletePageDialog', max-width='500') template(v-slot:activator='{ on }') v-list-item(v-on='on') diff --git a/client/components/admin/admin-pages-visualize.vue b/client/components/admin/admin-pages-visualize.vue index 116b38a9..3c9b20eb 100644 --- a/client/components/admin/admin-pages-visualize.vue +++ b/client/components/admin/admin-pages-visualize.vue @@ -104,7 +104,7 @@ export default { const truncatePath = path => _.take(path.split('/'), depth).join('/') const descendantsByChild = Object.entries(_.groupBy(descendants, page => truncatePath(page.path))) - .map(([childPath, descendantsGroup]) => [getPage(childPath), descendantsGroup]) + .map(([childPath, descendantsGroup]) => [getPage(childPath), _.sortBy(descendantsGroup, child => child.path)]) .map(([child, descendantsGroup]) => [child, _.filter(descendantsGroup, d => d.path !== child.path)]) return { diff --git a/client/components/admin/admin-pages.vue b/client/components/admin/admin-pages.vue index 0ca26de1..3f056eef 100644 --- a/client/components/admin/admin-pages.vue +++ b/client/components/admin/admin-pages.vue @@ -10,9 +10,9 @@ v-spacer v-btn.animated.fadeInDown.wait-p1s(icon, color='grey', outlined, @click='refresh') v-icon.grey--text mdi-refresh - v-btn.animated.fadeInDown.mx-3(color='primary', outlined, @click='recyclebin', disabled) - v-icon(left) mdi-delete-outline - span Recycle Bin + //- v-btn.animated.fadeInDown.mx-3(color='primary', outlined, @click='recyclebin', disabled) + //- v-icon(left) mdi-delete-outline + //- span Recycle Bin v-btn.animated.fadeInDown(color='primary', depressed, large, to='pages/visualize') v-icon(left) mdi-graph span Visualize diff --git a/client/components/admin/admin-security.vue b/client/components/admin/admin-security.vue index 7a8d305b..8c062c52 100644 --- a/client/components/admin/admin-security.vue +++ b/client/components/admin/admin-security.vue @@ -265,7 +265,7 @@ export default { securityOpenRedirect: true, securityIframe: true, securityReferrerPolicy: true, - securityTrustProxy: true, + securityTrustProxy: false, securitySRI: true, securityHSTS: false, securityHSTSDuration: 0, diff --git a/client/components/admin/admin-users-create.vue b/client/components/admin/admin-users-create.vue index 7128149e..a0350067 100644 --- a/client/components/admin/admin-users-create.vue +++ b/client/components/admin/admin-users-create.vue @@ -70,13 +70,13 @@ v-model='mustChangePwd' hide-details ) - v-checkbox( - color='primary' - label='Send a welcome email' - hide-details - v-model='sendWelcomeEmail' - disabled - ) + //- v-checkbox( + //- color='primary' + //- label='Send a welcome email' + //- hide-details + //- v-model='sendWelcomeEmail' + //- disabled + //- ) v-card-chin v-spacer v-btn(text, @click='isShown = false') Cancel diff --git a/client/components/admin/admin-users-edit.vue b/client/components/admin/admin-users-edit.vue index a9e20070..fb224fbd 100644 --- a/client/components/admin/admin-users-edit.vue +++ b/client/components/admin/admin-users-edit.vue @@ -337,12 +337,12 @@ .caption.grey--text.mt-3 {{$t('profile:activity.lastLoginOn')}} .body-2: strong {{ user.lastLoginAt | moment('LLLL') }} - v-card.mt-3.animated.fadeInUp.wait-p6s - v-toolbar(color='teal', dense, dark, flat) - v-icon.mr-2 mdi-file-document-box-multiple-outline - span Content - v-card-text - em.caption.grey--text Coming soon + //- v-card.mt-3.animated.fadeInUp.wait-p6s + //- v-toolbar(color='teal', dense, dark, flat) + //- v-icon.mr-2 mdi-file-document-box-multiple-outline + //- span Content + //- v-card-text + //- em.caption.grey--text Coming soon v-dialog(v-model='deleteUserDialog', max-width='500') v-card diff --git a/client/components/common/nav-header.vue b/client/components/common/nav-header.vue index d8fc3c80..e5f7acdf 100644 --- a/client/components/common/nav-header.vue +++ b/client/components/common/nav-header.vue @@ -15,7 +15,7 @@ prepend-inner-icon='mdi-magnify' :loading='searchIsLoading' @keyup.enter='searchEnter' - autocomplete='none' + autocomplete='off' ) v-layout(row) v-flex(xs5, md4) @@ -68,7 +68,7 @@ @blur='searchBlur' @keyup.down='searchMove(`down`)' @keyup.up='searchMove(`up`)' - autocomplete='none' + autocomplete='off' ) v-tooltip(bottom) template(v-slot:activator='{ on }') @@ -476,7 +476,11 @@ export default { window.location.assign('/logout') }, goHome () { - window.location.assign('/') + if (this.locales && this.locales.length > 0) { + window.location.assign(`/${this.locale}/home`) + } else { + window.location.assign('/') + } } } } diff --git a/client/components/editor/editor-asciidoc.vue b/client/components/editor/editor-asciidoc.vue index 296b2414..126ba370 100644 --- a/client/components/editor/editor-asciidoc.vue +++ b/client/components/editor/editor-asciidoc.vue @@ -228,7 +228,8 @@ export default { }) this.previewHTML = DOMPurify.sanitize($.html(), { - ADD_TAGS: ['foreignObject'] + ADD_TAGS: ['foreignObject'], + HTML_INTEGRATION_POINTS: { foreignobject: true } }) }, /** diff --git a/client/components/editor/editor-markdown.vue b/client/components/editor/editor-markdown.vue index 04b5c6aa..baee118d 100644 --- a/client/components/editor/editor-markdown.vue +++ b/client/components/editor/editor-markdown.vue @@ -200,7 +200,7 @@ import 'codemirror/addon/fold/foldgutter.css' import MarkdownIt from 'markdown-it' import mdAttrs from 'markdown-it-attrs' import mdDecorate from 'markdown-it-decorate' -import mdEmoji from 'markdown-it-emoji' +import { full as mdEmoji } from 'markdown-it-emoji' import mdTaskLists from 'markdown-it-task-lists' import mdExpandTabs from 'markdown-it-expand-tabs' import mdAbbr from 'markdown-it-abbr' @@ -454,7 +454,8 @@ export default { // this.$store.set('editor/content', newContent) this.processMarkers(this.cm.firstLine(), this.cm.lastLine()) this.previewHTML = DOMPurify.sanitize(md.render(newContent), { - ADD_TAGS: ['foreignObject'] + ADD_TAGS: ['foreignObject'], + HTML_INTEGRATION_POINTS: { foreignobject: true } }) this.$nextTick(() => { tabsetHelper.format() diff --git a/client/components/editor/editor-modal-media.vue b/client/components/editor/editor-modal-media.vue index 100a36df..67efe122 100644 --- a/client/components/editor/editor-modal-media.vue +++ b/client/components/editor/editor-modal-media.vue @@ -83,31 +83,31 @@ v-btn(icon, v-on='on', tile, small, @click.left='currentFileId = props.item.id') v-icon(color='grey darken-2') mdi-dots-horizontal v-list(nav, style='border-top: 5px solid #444;') - v-list-item(@click='', disabled) - v-list-item-avatar(size='24') - v-icon(color='teal') mdi-text-short - v-list-item-content {{$t('common:actions.properties')}} - template(v-if='props.item.kind === `IMAGE`') - v-list-item(@click='previewDialog = true', disabled) - v-list-item-avatar(size='24') - v-icon(color='green') mdi-image-search-outline - v-list-item-content {{$t('common:actions.preview')}} - v-list-item(@click='', disabled) - v-list-item-avatar(size='24') - v-icon(color='indigo') mdi-crop-rotate - v-list-item-content {{$t('common:actions.edit')}} - v-list-item(@click='', disabled) - v-list-item-avatar(size='24') - v-icon(color='purple') mdi-flash-circle - v-list-item-content {{$t('common:actions.optimize')}} + //- v-list-item(@click='', disabled) + //- v-list-item-avatar(size='24') + //- v-icon(color='teal') mdi-text-short + //- v-list-item-content {{$t('common:actions.properties')}} + //- template(v-if='props.item.kind === `IMAGE`') + //- v-list-item(@click='previewDialog = true', disabled) + //- v-list-item-avatar(size='24') + //- v-icon(color='green') mdi-image-search-outline + //- v-list-item-content {{$t('common:actions.preview')}} + //- v-list-item(@click='', disabled) + //- v-list-item-avatar(size='24') + //- v-icon(color='indigo') mdi-crop-rotate + //- v-list-item-content {{$t('common:actions.edit')}} + //- v-list-item(@click='', disabled) + //- v-list-item-avatar(size='24') + //- v-icon(color='purple') mdi-flash-circle + //- v-list-item-content {{$t('common:actions.optimize')}} v-list-item(@click='openRenameDialog') v-list-item-avatar(size='24') v-icon(color='orange') mdi-keyboard-outline v-list-item-content {{$t('common:actions.rename')}} - v-list-item(@click='', disabled) - v-list-item-avatar(size='24') - v-icon(color='blue') mdi-file-move - v-list-item-content {{$t('common:actions.move')}} + //- v-list-item(@click='', disabled) + //- v-list-item-avatar(size='24') + //- v-icon(color='blue') mdi-file-move + //- v-list-item-content {{$t('common:actions.move')}} v-list-item(@click='deleteDialog = true') v-list-item-avatar(size='24') v-icon(color='red') mdi-file-hidden @@ -154,25 +154,25 @@ v-spacer v-btn.px-4(color='teal', dark, @click='upload') {{$t('common:actions.upload')}} - v-card.mt-3.radius-7.animated.fadeInRight.wait-p4s(:light='!$vuetify.theme.dark', :dark='$vuetify.theme.dark') - v-card-text.pb-0 - v-toolbar.radius-7(:color='$vuetify.theme.dark ? `teal` : `teal lighten-5`', dense, flat) - v-icon.mr-3(:color='$vuetify.theme.dark ? `white` : `teal`') mdi-cloud-download - .body-2(:class='$vuetify.theme.dark ? `white--text` : `teal--text`') {{$t('editor:assets.fetchImage')}} - v-spacer - v-chip(label, color='white', small).teal--text coming soon - v-text-field.mt-3( - v-model='remoteImageUrl' - outlined - color='teal' - single-line - placeholder='https://example.com/image.jpg' - ) - v-divider - v-card-actions.pa-3 - .caption.grey--text.text-darken-2 Max 5 MB - v-spacer - v-btn.px-4(color='teal', disabled) {{$t('common:actions.fetch')}} + //- v-card.mt-3.radius-7.animated.fadeInRight.wait-p4s(:light='!$vuetify.theme.dark', :dark='$vuetify.theme.dark') + //- v-card-text.pb-0 + //- v-toolbar.radius-7(:color='$vuetify.theme.dark ? `teal` : `teal lighten-5`', dense, flat) + //- v-icon.mr-3(:color='$vuetify.theme.dark ? `white` : `teal`') mdi-cloud-download + //- .body-2(:class='$vuetify.theme.dark ? `white--text` : `teal--text`') {{$t('editor:assets.fetchImage')}} + //- v-spacer + //- v-chip(label, color='white', small).teal--text coming soon + //- v-text-field.mt-3( + //- v-model='remoteImageUrl' + //- outlined + //- color='teal' + //- single-line + //- placeholder='https://example.com/image.jpg' + //- ) + //- v-divider + //- v-card-actions.pa-3 + //- .caption.grey--text.text-darken-2 Max 5 MB + //- v-spacer + //- v-btn.px-4(color='teal', disabled) {{$t('common:actions.fetch')}} v-card.mt-3.radius-7.animated.fadeInRight.wait-p4s(:light='!$vuetify.theme.dark', :dark='$vuetify.theme.dark') v-card-text.pb-0 diff --git a/client/components/editor/editor-modal-properties.vue b/client/components/editor/editor-modal-properties.vue index 0738b333..a6ed1af3 100644 --- a/client/components/editor/editor-modal-properties.vue +++ b/client/components/editor/editor-modal-properties.vue @@ -21,7 +21,7 @@ v-tab {{$t('editor:props.info')}} v-tab {{$t('editor:props.scheduling')}} v-tab(:disabled='!hasScriptPermission') {{$t('editor:props.scripts')}} - v-tab(disabled) {{$t('editor:props.social')}} + //- v-tab(disabled) {{$t('editor:props.social')}} v-tab(:disabled='!hasStylePermission') {{$t('editor:props.styles')}} v-tab-item(transition='fade-transition', reverse-transition='fade-transition') v-card-text.pt-5 @@ -196,42 +196,42 @@ .editor-props-codeeditor-hint .caption {{$t('editor:props.htmlHint')}} - v-tab-item(transition='fade-transition', reverse-transition='fade-transition') - v-card-text - .overline {{$t('editor:props.socialFeatures')}} - v-switch( - :label='$t(`editor:props.allowComments`)' - v-model='isPublished' - color='primary' - :hint='$t(`editor:props.allowCommentsHint`)' - persistent-hint - inset - ) - v-switch( - :label='$t(`editor:props.allowRatings`)' - v-model='isPublished' - color='primary' - :hint='$t(`editor:props.allowRatingsHint`)' - persistent-hint - disabled - inset - ) - v-switch( - :label='$t(`editor:props.displayAuthor`)' - v-model='isPublished' - color='primary' - :hint='$t(`editor:props.displayAuthorHint`)' - persistent-hint - inset - ) - v-switch( - :label='$t(`editor:props.displaySharingBar`)' - v-model='isPublished' - color='primary' - :hint='$t(`editor:props.displaySharingBarHint`)' - persistent-hint - inset - ) + //- v-tab-item(transition='fade-transition', reverse-transition='fade-transition') + //- v-card-text + //- .overline {{$t('editor:props.socialFeatures')}} + //- v-switch( + //- :label='$t(`editor:props.allowComments`)' + //- v-model='isPublished' + //- color='primary' + //- :hint='$t(`editor:props.allowCommentsHint`)' + //- persistent-hint + //- inset + //- ) + //- v-switch( + //- :label='$t(`editor:props.allowRatings`)' + //- v-model='isPublished' + //- color='primary' + //- :hint='$t(`editor:props.allowRatingsHint`)' + //- persistent-hint + //- disabled + //- inset + //- ) + //- v-switch( + //- :label='$t(`editor:props.displayAuthor`)' + //- v-model='isPublished' + //- color='primary' + //- :hint='$t(`editor:props.displayAuthorHint`)' + //- persistent-hint + //- inset + //- ) + //- v-switch( + //- :label='$t(`editor:props.displaySharingBar`)' + //- v-model='isPublished' + //- color='primary' + //- :hint='$t(`editor:props.displaySharingBarHint`)' + //- persistent-hint + //- inset + //- ) v-tab-item(:transition='false', :reverse-transition='false') .editor-props-codeeditor-title @@ -276,10 +276,10 @@ export default { currentTab: 0, cm: null, rules: { - required: value => !!value || 'This field is required.', - path: value => { - return filenamePattern.test(value) || 'Invalid path. Please ensure it does not contain special characters, or begin/end in a slash or hashtag string.' - } + required: value => !!value || 'This field is required.', + path: value => { + return filenamePattern.test(value) || 'Invalid path. Please ensure it does not contain special characters, or begin/end in a slash or hashtag string.' + } } } }, @@ -334,7 +334,7 @@ export default { this.loadEditor(this.$refs.codejs, 'html') }, 100) }) - } else if (newValue === 4) { + } else if (newValue === 3) { this.$nextTick(() => { setTimeout(() => { this.loadEditor(this.$refs.codecss, 'css') diff --git a/client/components/login.vue b/client/components/login.vue index f74a4744..0bbaa2a5 100644 --- a/client/components/login.vue +++ b/client/components/login.vue @@ -641,19 +641,25 @@ export default { } else { this.loaderColor = 'green darken-1' this.loaderTitle = this.$t('auth:loginSuccess') - Cookies.set('jwt', respObj.jwt, { expires: 365 }) + Cookies.set('jwt', respObj.jwt, { expires: 365, secure: window.location.protocol === 'https:' }) _.delay(() => { const loginRedirect = Cookies.get('loginRedirect') + const isValidRedirect = loginRedirect && loginRedirect.startsWith('/') && !loginRedirect.startsWith('//') && !loginRedirect.includes('://') if (loginRedirect === '/' && respObj.redirect) { Cookies.remove('loginRedirect') window.location.replace(respObj.redirect) - } else if (loginRedirect) { + } else if (isValidRedirect) { Cookies.remove('loginRedirect') window.location.replace(loginRedirect) - } else if (respObj.redirect) { - window.location.replace(respObj.redirect) } else { - window.location.replace('/') + if (loginRedirect) { + Cookies.remove('loginRedirect') + } + if (respObj.redirect) { + window.location.replace(respObj.redirect) + } else { + window.location.replace('/') + } } }, 1000) } diff --git a/client/components/profile/profile.vue b/client/components/profile/profile.vue index 345476d2..dfb0bba8 100644 --- a/client/components/profile/profile.vue +++ b/client/components/profile/profile.vue @@ -129,41 +129,43 @@ //- v-btn(color='purple darken-4', disabled).ml-0 Enable 2FA //- v-btn(color='purple darken-4', dark, depressed, disabled).ml-0 Disable 2FA template(v-if='user.providerKey === `local`') - v-divider.mt-3 - v-subheader.pl-0: span.subtitle-2 {{$t('profile:auth.changePassword')}} - v-text-field( - ref='iptCurrentPass' - v-model='currentPass' - outlined - :label='$t(`profile:auth.currentPassword`)' - type='password' - prepend-inner-icon='mdi-form-textbox-password' - ) - v-text-field( - ref='iptNewPass' - v-model='newPass' - outlined - :label='$t(`profile:auth.newPassword`)' - type='password' - prepend-inner-icon='mdi-form-textbox-password' - autocomplete='off' - counter='255' - loading - ) - password-strength(slot='progress', v-model='newPass') - v-text-field( - ref='iptVerifyPass' - v-model='verifyPass' - outlined - :label='$t(`profile:auth.verifyPassword`)' - type='password' - prepend-inner-icon='mdi-form-textbox-password' - autocomplete='off' - hide-details - ) + form#change-password-form(@submit.prevent='changePassword') + v-divider.mt-3 + v-subheader.pl-0: span.subtitle-2 {{$t('profile:auth.changePassword')}} + v-text-field( + ref='iptCurrentPass' + v-model='currentPass' + outlined + :label='$t(`profile:auth.currentPassword`)' + type='password' + prepend-inner-icon='mdi-form-textbox-password' + autocomplete='current-password' + ) + v-text-field( + ref='iptNewPass' + v-model='newPass' + outlined + :label='$t(`profile:auth.newPassword`)' + type='password' + prepend-inner-icon='mdi-form-textbox-password' + autocomplete='off' + counter='255' + loading + ) + password-strength(slot='progress', v-model='newPass') + v-text-field( + ref='iptVerifyPass' + v-model='verifyPass' + outlined + :label='$t(`profile:auth.verifyPassword`)' + type='password' + prepend-inner-icon='mdi-form-textbox-password' + autocomplete='off' + hide-details + ) v-card-chin(v-if='user.providerKey === `local`') v-spacer - v-btn.px-4(color='purple darken-4', dark, depressed, @click='changePassword', :loading='changePassLoading') + v-btn.px-4(color='purple darken-4', dark, depressed, :loading='changePassLoading', type='submit', form='change-password-form') v-icon(left) mdi-progress-check span {{$t('profile:auth.changePassword')}} v-flex(lg6 xs12) @@ -755,7 +757,7 @@ export default { }) const resp = _.get(respRaw, 'data.users.updateProfile.responseResult', {}) if (resp.succeeded) { - Cookies.set('jwt', _.get(respRaw, 'data.users.updateProfile.jwt', ''), { expires: 365 }) + Cookies.set('jwt', _.get(respRaw, 'data.users.updateProfile.jwt', ''), { expires: 365, secure: window.location.protocol === 'https:' }) this.$store.set('user/name', this.user.name) this.$store.commit('showNotification', { message: this.$t('profile:save.success'), @@ -863,7 +865,7 @@ export default { this.currentPass = '' this.newPass = '' this.verifyPass = '' - Cookies.set('jwt', _.get(respRaw, 'data.users.changePassword.jwt', ''), { expires: 365 }) + Cookies.set('jwt', _.get(respRaw, 'data.users.changePassword.jwt', ''), { expires: 365, secure: window.location.protocol === 'https:' }) this.$store.commit('showNotification', { message: this.$t('profile:auth.changePassSuccess'), style: 'success', diff --git a/client/components/source.vue b/client/components/source.vue index 6da6906a..2e6b8baa 100644 --- a/client/components/source.vue +++ b/client/components/source.vue @@ -20,8 +20,7 @@ v-card.grey.radius-7(flat, :class='$vuetify.theme.dark ? `darken-4` : `lighten-4`') v-card-text pre - code - slot + slot nav-footer notify diff --git a/client/components/tags.vue b/client/components/tags.vue index 3d717b38..56bc6cbb 100644 --- a/client/components/tags.vue +++ b/client/components/tags.vue @@ -98,6 +98,7 @@ :search='innerSearch' :loading='isLoading' :options.sync='pagination' + @page-count='pageTotal = $event' hide-default-footer ref='dude' ) @@ -183,6 +184,7 @@ export default { sortDesc: [false] }, pages: [], + pageTotal: 0, isLoading: true, scrollStyle: { vuescroll: {}, @@ -214,9 +216,6 @@ export default { tagsSelected () { return _.filter(this.tags, t => _.includes(this.selection, t.tag)) }, - pageTotal () { - return Math.ceil(this.pages.length / this.pagination.itemsPerPage) - }, orderByItems () { return [ { text: this.$t('tags:orderByField.creationDate'), value: 'createdAt' }, diff --git a/client/store/site.js b/client/store/site.js index 979468c7..0e3369de 100644 --- a/client/store/site.js +++ b/client/store/site.js @@ -5,6 +5,7 @@ import { make } from 'vuex-pathify' const state = { company: siteConfig.company, contentLicense: siteConfig.contentLicense, + footerOverride: siteConfig.footerOverride, dark: siteConfig.darkMode, tocPosition: siteConfig.tocPosition, mascot: true, diff --git a/client/themes/default/components/nav-footer.vue b/client/themes/default/components/nav-footer.vue index 08e44fcd..93368daa 100644 --- a/client/themes/default/components/nav-footer.vue +++ b/client/themes/default/components/nav-footer.vue @@ -1,7 +1,9 @@