Merge branch 'main' of github.com:openziti/zrok into python-sdk

This commit is contained in:
Cam 2023-11-16 10:56:38 -06:00
commit 7af28dada9
No known key found for this signature in database
GPG Key ID: 367B7C7EBD84A8BD
90 changed files with 1903 additions and 645 deletions

View File

@ -10,6 +10,10 @@ on:
- 'docs/**'
- 'website/**'
# cancel older, redundant builds that haven't started yet
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
jobs:
ubuntu-build:
name: Build Linux AMD64 CLI
@ -27,22 +31,29 @@ jobs:
with:
node-version: 18.x
- run: npm install
- name: install ui node modules
shell: bash
run: npm install
working-directory: ui
- run: npm run build
- name: build node ui
shell: bash
run: npm run build
working-directory: ui
env:
CI: "true"
- name: go install
shell: bash
run: go install -ldflags "-X github.com/openziti/zrok/build.Version=${{ github.ref }} -X github.com/openziti/zrok/build.Hash=${{ github.sha }}" ./...
- name: test
- name: go test
shell: bash
run: go test -v ./...
- name: solve GOBIN
id: solve_go_bin
shell: bash
run: |
echo DEBUG: go_path="$(go env GOPATH)"
echo go_bin="$(go env GOPATH)/bin" >> $GITHUB_OUTPUT
@ -53,6 +64,7 @@ jobs:
name: linux-amd64
path: ${{ steps.solve_go_bin.outputs.go_bin }}/zrok
if-no-files-found: error
# build a release candidate container image for branches named "main" or like "v*"
rc-container-build:
needs: ubuntu-build
@ -62,6 +74,7 @@ jobs:
steps:
- name: Set a container image tag from the branch name
id: slug
shell: bash
run: |
echo branch_tag=$(sed 's/[^a-z0-9_-]/__/gi' <<< "${GITHUB_REF#refs/heads/}") >> $GITHUB_OUTPUT
@ -86,7 +99,7 @@ jobs:
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_API_USER }}
username: ${{ vars.DOCKER_HUB_API_USER || secrets.DOCKER_HUB_API_USER }}
password: ${{ secrets.DOCKER_HUB_API_TOKEN }}
- name: Set Up Container Image Tags for zrok CLI Container
@ -94,11 +107,10 @@ jobs:
ZROK_CONTAINER_IMAGE_REPO: ${{ vars.ZROK_CONTAINER_IMAGE_REPO || 'openziti/zrok' }}
ZROK_CONTAINER_IMAGE_TAG: ${{ steps.slug.outputs.branch_tag }}
id: tagprep_cli
shell: bash
run: |
DOCKER_TAGS=""
DOCKER_TAGS="${ZROK_CONTAINER_IMAGE_REPO}:${ZROK_CONTAINER_IMAGE_TAG}"
echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
echo DOCKER_TAGS="${ZROK_CONTAINER_IMAGE_REPO}:${ZROK_CONTAINER_IMAGE_TAG}" \
| tee -a $GITHUB_OUTPUT
- name: Build & Push Linux AMD64 CLI Container Image to Hub
uses: docker/build-push-action@v3

View File

@ -5,6 +5,10 @@ on:
branches:
- main
# allow GITHUB_TOKEN to be used by the peaceiris/actions-gh-pages action to push to gh-pages branch
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest

View File

@ -6,16 +6,18 @@ on:
jobs:
update-brew:
if: github.repository_owner == 'openziti'
runs-on: ubuntu-latest
steps:
- name: Extract Version
id: extract-version
run: |
printf "::set-output name=%s::%s\n" tag-name "${GITHUB_REF#refs/tags/}"
- uses: mislav/bump-homebrew-formula-action@v2
if: "!contains(github.ref, '-')"
echo "tag-name=${GITHUB_REF#refs/tags/}" | tee -a ${GITHUB_OUTPUT}
- uses: mislav/bump-homebrew-formula-action@v3.1
if: ${{ !contains(github.ref, '-') }}
with:
formula-name: zrok
download-url: https://github.com/openziti/zrok/archive/${{ steps.extract-version.outputs.tag-name }}.tar.gz
download-url: https://github.com/openziti/zrok/archive/refs/tags/${{ steps.extract-version.outputs.tag-name }}.tar.gz
env:
COMMITTER_TOKEN: ${{ secrets.BREW_COMMITTER_TOKEN }}

View File

@ -24,7 +24,7 @@ jobs:
id: semver
run: |
zrok_semver=${RELEASE_REF#refs/tags/}
echo "zrok_semver=${zrok_semver#v}" >> $GITHUB_OUTPUT
echo "zrok_semver=${zrok_semver#v}" | tee -a $GITHUB_OUTPUT
- name: Checkout Workspace
uses: actions/checkout@v3
@ -67,7 +67,7 @@ jobs:
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_API_USER }}
username: ${{ vars.DOCKER_HUB_API_USER || secrets.DOCKER_HUB_API_USER }}
password: ${{ secrets.DOCKER_HUB_API_TOKEN }}
- name: Set Up Container Image Tags for zrok CLI Container
@ -76,10 +76,7 @@ jobs:
ZROK_VERSION: ${{ steps.semver.outputs.zrok_semver }}
id: tagprep_cli
run: |
DOCKER_TAGS=""
DOCKER_TAGS="${RELEASE_REPO}:${ZROK_VERSION},${RELEASE_REPO}:latest"
echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
echo DOCKER_TAGS="${RELEASE_REPO}:${ZROK_VERSION},${RELEASE_REPO}:latest" | tee -a $GITHUB_OUTPUT
# this is the CLI image with the Linux binary for each
# arch that was downloaded in ./dist/
@ -95,94 +92,3 @@ jobs:
DOCKER_BUILD_DIR=./docker/images/zrok
ARTIFACTS_DIR=./dist
push: true
# - name: Set Up Container Image Tags for zrok Controller Container
# env:
# RELEASE_REPO: openziti/zrok-controller
# ZROK_VERSION: ${{ steps.semver.outputs.zrok_semver }}
# id: tagprep_ctrl
# run: |
# DOCKER_TAGS=""
# DOCKER_TAGS="${RELEASE_REPO}:${ZROK_VERSION},${RELEASE_REPO}:latest"
# echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
# echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
# # This is a use-case image based on the minimal CLI image. It needs the
# # ZROK_VERSION env var so it can build from the versioned image that
# # we pushed in the prior step.
# - name: Build & Push Multi-Platform Controller Container Image to Hub
# uses: docker/build-push-action@v3
# with:
# builder: ${{ steps.buildx.outputs.name }}
# context: ${{ github.workspace }}/docker/images/zrok-controller/
# platforms: linux/amd64,linux/arm64
# tags: ${{ steps.tagprep_ctrl.outputs.DOCKER_TAGS }}
# build-args: |
# ZROK_VERSION=${{ env.ZROK_VERSION }}
# push: true
# - name: Set Up Container Image Tags for zrok Frontend Container
# env:
# RELEASE_REPO: openziti/zrok-frontend
# ZROK_VERSION: ${{ steps.semver.outputs.zrok_semver }}
# id: tagprep_frontend
# run: |
# DOCKER_TAGS=""
# DOCKER_TAGS="${RELEASE_REPO}:${ZROK_VERSION},${RELEASE_REPO}:latest"
# echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
# echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
# - name: Build & Push Multi-Platform Frontend Container Image to Hub
# uses: docker/build-push-action@v3
# with:
# builder: ${{ steps.buildx.outputs.name }}
# context: ${{ github.workspace }}/docker/images/zrok-frontend/
# platforms: linux/amd64,linux/arm64
# tags: ${{ steps.tagprep_frontend.outputs.DOCKER_TAGS }}
# build-args: |
# ZROK_VERSION=${{ env.ZROK_VERSION }}
# push: true
# - name: Set Up Container Image Tags for zrok Share Container
# env:
# RELEASE_REPO: openziti/zrok-share
# ZROK_VERSION: ${{ steps.semver.outputs.zrok_semver }}
# id: tagprep_share
# run: |
# DOCKER_TAGS=""
# DOCKER_TAGS="${RELEASE_REPO}:${ZROK_VERSION},${RELEASE_REPO}:latest"
# echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
# echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
# - name: Build & Push Multi-Platform zrok Share Container Image to Hub
# uses: docker/build-push-action@v3
# with:
# builder: ${{ steps.buildx.outputs.name }}
# context: ${{ github.workspace }}/docker/images/zrok-share/
# platforms: linux/amd64,linux/arm64
# tags: ${{ steps.tagprep_share.outputs.DOCKER_TAGS }}
# build-args: |
# ZROK_VERSION=${{ env.ZROK_VERSION }}
# push: true
# - name: Set Up Container Image Tags for zrok Access Container
# env:
# RELEASE_REPO: openziti/zrok-access
# ZROK_VERSION: ${{ steps.semver.outputs.zrok_semver }}
# id: tagprep_access
# run: |
# DOCKER_TAGS=""
# DOCKER_TAGS="${RELEASE_REPO}:${ZROK_VERSION},${RELEASE_REPO}:latest"
# echo "DEBUG: DOCKER_TAGS=${DOCKER_TAGS}"
# echo DOCKER_TAGS="${DOCKER_TAGS}" >> $GITHUB_OUTPUT
# - name: Build & Push Multi-Platform zrok Access Container Image to Hub
# uses: docker/build-push-action@v3
# with:
# builder: ${{ steps.buildx.outputs.name }}
# context: ${{ github.workspace }}/docker/images/zrok-access/
# platforms: linux/amd64,linux/arm64
# tags: ${{ steps.tagprep_access.outputs.DOCKER_TAGS }}
# build-args: |
# ZROK_VERSION=${{ env.ZROK_VERSION }}
# push: true

View File

@ -9,6 +9,11 @@ on:
permissions:
contents: write
env:
ZITI_DEB_PROD_REPO: ${{ vars.ZITI_DEB_PROD_REPO || 'zitipax-openziti-deb-stable' }}
ZITI_RPM_PROD_REPO: ${{ vars.ZITI_RPM_PROD_REPO || 'zitipax-openziti-rpm-stable' }}
JFROG_CLI_VERSION: ${{ vars.JFROG_CLI_VERSION || '2.50.4' }}
jobs:
build-linux-amd64:
runs-on: ubuntu-20.04
@ -39,7 +44,7 @@ jobs:
env:
CI: "true"
- uses: goreleaser/goreleaser-action@v2
- uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
@ -52,6 +57,34 @@ jobs:
name: release-builds
path: ./dist/*.gz
- name: Configure jFrog CLI
uses: jfrog/setup-jfrog-cli@v3
with:
version: ${{ env.JFROG_CLI_VERSION }}
env:
JF_ENV_1: ${{ secrets.ZITI_ARTIFACTORY_CLI_CONFIG_PACKAGE_UPLOAD }}
- name: Upload RPM to Artifactory release repo
shell: bash
run: |
for RPM in ./dist/*.rpm; do
echo "INFO: Uploading $RPM"
jf rt upload --recursive=false --flat=true \
"$RPM" \
${{ env.ZITI_RPM_PROD_REPO }}/redhat/x86_64/
done
- name: Upload DEB to Artifactory release repo
shell: bash
run: |
for DEB in ./dist/*.deb; do
echo "INFO: Uploading $DEB"
jf rt upload --recursive=false --flat=true \
--deb=debian/main/amd64 \
"$DEB" \
${{ env.ZITI_DEB_PROD_REPO }}/pool/zrok/amd64/
done
build-linux-arm64:
runs-on: ubuntu-20.04
steps:
@ -94,6 +127,34 @@ jobs:
name: release-builds
path: ./dist/*.gz
- name: Configure jFrog CLI
uses: jfrog/setup-jfrog-cli@v3
with:
version: ${{ env.JFROG_CLI_VERSION }}
env:
JF_ENV_1: ${{ secrets.ZITI_ARTIFACTORY_CLI_CONFIG_PACKAGE_UPLOAD }}
- name: Upload RPM to Artifactory release repo
shell: bash
run: |
for RPM in ./dist/*.rpm; do
echo "INFO: Uploading $RPM"
jf rt upload --recursive=false --flat=true \
"$RPM" \
${{ env.ZITI_RPM_PROD_REPO }}/redhat/aarch64/
done
- name: Upload DEB to Artifactory release repo
shell: bash
run: |
for DEB in ./dist/*.deb; do
echo "INFO: Uploading $DEB"
jf rt upload --recursive=false --flat=true \
--deb=debian/main/arm64 \
"$DEB" \
${{ env.ZITI_DEB_PROD_REPO }}/pool/zrok/arm64/
done
build-linux-arm:
runs-on: ubuntu-20.04
steps:
@ -136,7 +197,36 @@ jobs:
name: release-builds
path: ./dist/*.gz
- name: Configure jFrog CLI
uses: jfrog/setup-jfrog-cli@v3
with:
version: ${{ env.JFROG_CLI_VERSION }}
env:
JF_ENV_1: ${{ secrets.ZITI_ARTIFACTORY_CLI_CONFIG_PACKAGE_UPLOAD }}
- name: Upload RPM to Artifactory release repo
shell: bash
run: |
for RPM in ./dist/*.rpm; do
echo "INFO: Uploading $RPM"
jf rt upload --recursive=false --flat=true \
"$RPM" \
${{ env.ZITI_RPM_PROD_REPO }}/redhat/armv7/
done
- name: Upload DEB to Artifactory release repo
shell: bash
run: |
for DEB in ./dist/*.deb; do
echo "INFO: Uploading $DEB"
jf rt upload --recursive=false --flat=true \
--deb=debian/main/armv7 \
"$DEB" \
${{ env.ZITI_DEB_PROD_REPO }}/pool/zrok/armv7/
done
build-darwin:
if: github.repository_owner == 'openziti' || vars.ZROK_SKIP_MACOS_BUILD == 'false'
runs-on: macos-latest
steps:
- name: import distribution cert
@ -145,10 +235,6 @@ jobs:
p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }}
p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }}
- run: |
brew tap mitchellh/gon
brew install mitchellh/gon/gon
- uses: actions/checkout@v3
with:
fetch-depth: 0
@ -188,6 +274,7 @@ jobs:
path: ./dist/*.gz
build-windows:
if: github.repository_owner == 'openziti' || vars.ZROK_SKIP_WINDOWS_BUILD == 'false'
runs-on: ubuntu-latest
steps:
- run: sudo apt update
@ -230,6 +317,15 @@ jobs:
path: ./dist/*.gz
publish-release:
# allow skipped but not failed
if: ${{
!cancelled()
&& (needs.build-linux-amd64.result == 'success' || needs.build-linux-amd64.result == 'skipped')
&& (needs.build-linux-arm.result == 'success' || needs.build-linux-amd.result == 'skipped')
&& (needs.build-linux-arm64.result == 'success' || needs.build-linux-amd64.result == 'skipped')
&& (needs.build-darwin.result == 'success' || needs.build-darwin.result == 'skipped')
&& (needs.build-windows.result == 'success' || needs.build-windows.result == 'skipped')
}}
needs: [build-linux-amd64, build-linux-arm, build-linux-arm64, build-darwin, build-windows]
runs-on: ubuntu-latest
steps:

View File

@ -10,7 +10,12 @@ builds:
goarch:
- amd64
hooks:
post: gon -log-level=info build/gon-amd64.hcl
post:
- cmd: 'codesign -s "Developer ID Application: NetFoundry Inc" -v dist/zrok-amd64_darwin_amd64_v1/zrok --options=runtime'
output: true
- cmd: zip "dist/zrok-amd64_darwin_amd64_v1/zrok.zip" dist/zrok-amd64_darwin_amd64_v1/zrok
- cmd: xcrun notarytool submit "dist/zrok-amd64_darwin_amd64_v1/zrok.zip" --apple-id {{ .Env.AC_USERNAME }} --password {{ .Env.AC_PASSWORD }} --team-id MN5S649TXM --wait
output: true
- id: zrok-arm64
main: ./cmd/zrok
@ -23,4 +28,9 @@ builds:
goarch:
- arm64
hooks:
post: gon -log-level=info build/gon-arm64.hcl
post:
- cmd: 'codesign -s "Developer ID Application: NetFoundry Inc" -v dist/zrok-arm64_darwin_arm64/zrok --options=runtime'
output: true
- cmd: zip "dist/zrok-arm64_darwin_arm64/zrok.zip" dist/zrok-arm64_darwin_arm64/zrok
- cmd: xcrun notarytool submit "dist/zrok-arm64_darwin_arm64/zrok.zip" --apple-id {{ .Env.AC_USERNAME }} --password {{ .Env.AC_PASSWORD }} --team-id MN5S649TXM --wait
output: true

View File

@ -13,3 +13,124 @@ builds:
- arm64
goarm:
- 8
nfpms:
- package_name: zrok
id: zrok-cli
vendor: NetFoundry
homepage: https://zrok.io/
maintainer: support@zrok.io
description: |-
zrok is a next-generation sharing platform, designed to make sharing network and file resources simple and
secure.
license: Apache 2.0
# Build IDs for the builds you want to create NFPM packages for.
builds:
- zrok-armv8
# Formats to be generated.
formats:
- deb
- rpm
# {{ .ConventionalFileName }} satisfies the RPM name convention.
file_name_template: "{{ .ConventionalFileName }}"
# Umask to be used on files without explicit mode set. (overridable)
umask: 0o002
# Package version within this release version.
release: 1
# Section.
section: default
# Priority.
priority: optional
# GoReleaser will automatically add the binaries here
bindir: /opt/openziti/bin
# Contents to add to the package.
contents:
- src: /opt/openziti/bin/zrok
dst: /usr/bin/zrok
type: "symlink"
- package_name: zrok-share
id: zrok-share
vendor: NetFoundry
homepage: https://zrok.io/
maintainer: support@zrok.io
description: |-
This package provides zrok-share.service. To enable, edit the "/opt/openziti/etc/zrok/zrok-share.env" file with the
desired target for sharing, and run "systemctl enable --now zrok-share.service".
license: Apache 2.0
# do not bundle the built binaries, only supporting files
meta: true
# Formats to be generated.
formats:
- deb
- rpm
# {{ .ConventionalFileName }} satisfies the RPM name convention.
file_name_template: "{{ .ConventionalFileName }}"
# Umask to be used on files without explicit mode set. (overridable)
umask: 0o002
# Package version within this release version.
release: 1
# Section.
section: default
# Priority.
priority: optional
# GoReleaser will automatically add the binaries here
dependencies:
- zrok
# this allows users to satisfy the requirement for jq another way, not with the package manager, e.g.
# apt install --no-recommends zrok-share
recommends:
- jq
overrides:
# yum and dnf do not automatically install "weak deps" aka "recommends", so we need to add them as a dependency
rpm:
dependencies:
- zrok
- jq
# Contents to add to the package.
contents:
- dst: /lib/systemd/system/
src: ./nfpm/zrok-share.service
- dst: /opt/openziti/etc/zrok
type: dir
file_info:
mode: 0755
- dst: /opt/openziti/bin/
src: ./nfpm/zrok-share.bash
file_info:
mode: 0755
- dst: /opt/openziti/bin/
src: ./nfpm/zrok-enable.bash
file_info:
mode: 0755
- dst: /opt/openziti/etc/zrok/
src: ./nfpm/zrok-share.env
type: config|noreplace
- dst: /opt/openziti/etc/zrok/
src: ./etc/caddy/multiple_upstream.Caddyfile
type: config|noreplace

View File

@ -12,4 +12,125 @@ builds:
goarch:
- arm
goarm:
- 7
- 7
nfpms:
- package_name: zrok
id: zrok-cli
vendor: NetFoundry
homepage: https://zrok.io/
maintainer: support@zrok.io
description: |-
zrok is a next-generation sharing platform, designed to make sharing network and file resources simple and
secure.
license: Apache 2.0
# Build IDs for the builds you want to create NFPM packages for.
builds:
- zrok-armv7
# Formats to be generated.
formats:
- deb
- rpm
# {{ .ConventionalFileName }} satisfies the RPM name convention.
file_name_template: "{{ .ConventionalFileName }}"
# Umask to be used on files without explicit mode set. (overridable)
umask: 0o002
# Package version within this release version.
release: 1
# Section.
section: default
# Priority.
priority: optional
# GoReleaser will automatically add the binaries here
bindir: /opt/openziti/bin
# Contents to add to the package.
contents:
- src: /opt/openziti/bin/zrok
dst: /usr/bin/zrok
type: "symlink"
- package_name: zrok-share
id: zrok-share
vendor: NetFoundry
homepage: https://zrok.io/
maintainer: support@zrok.io
description: |-
This package provides zrok-share.service. To enable, edit the "/opt/openziti/etc/zrok/zrok-share.env" file with the
desired target for sharing, and run "systemctl enable --now zrok-share.service".
license: Apache 2.0
# do not bundle the built binaries, only supporting files
meta: true
# Formats to be generated.
formats:
- deb
- rpm
# {{ .ConventionalFileName }} satisfies the RPM name convention.
file_name_template: "{{ .ConventionalFileName }}"
# Umask to be used on files without explicit mode set. (overridable)
umask: 0o002
# Package version within this release version.
release: 1
# Section.
section: default
# Priority.
priority: optional
# GoReleaser will automatically add the binaries here
dependencies:
- zrok
# this allows users to satisfy the requirement for jq another way, not with the package manager, e.g.
# apt install --no-recommends zrok-share
recommends:
- jq
overrides:
# yum and dnf do not automatically install "weak deps" aka "recommends", so we need to add them as a dependency
rpm:
dependencies:
- zrok
- jq
# Contents to add to the package.
contents:
- dst: /lib/systemd/system/
src: ./nfpm/zrok-share.service
- dst: /opt/openziti/etc/zrok
type: dir
file_info:
mode: 0755
- dst: /opt/openziti/bin/
src: ./nfpm/zrok-share.bash
file_info:
mode: 0755
- dst: /opt/openziti/bin/
src: ./nfpm/zrok-enable.bash
file_info:
mode: 0755
- dst: /opt/openziti/etc/zrok/
src: ./nfpm/zrok-share.env
type: config|noreplace
- dst: /opt/openziti/etc/zrok/
src: ./etc/caddy/multiple_upstream.Caddyfile
type: config|noreplace

View File

@ -1,5 +1,6 @@
builds:
- main: ./cmd/zrok
- id: zrok-amd64
main: ./cmd/zrok
binary: zrok
ldflags: "-s -w -X github.com/openziti/zrok/build.Version={{.Tag}} -X github.com/openziti/zrok/build.Hash={{.ShortCommit}}"
env:
@ -8,3 +9,124 @@ builds:
- linux
goarch:
- amd64
nfpms:
- package_name: zrok
id: zrok-cli
vendor: NetFoundry
homepage: https://zrok.io/
maintainer: support@zrok.io
description: |-
zrok is a next-generation sharing platform, designed to make sharing network and file resources simple and
secure.
license: Apache 2.0
# Build IDs for the builds you want to create NFPM packages for.
builds:
- zrok-amd64
# Formats to be generated.
formats:
- deb
- rpm
# {{ .ConventionalFileName }} satisfies the RPM name convention.
file_name_template: "{{ .ConventionalFileName }}"
# Umask to be used on files without explicit mode set. (overridable)
umask: 0o002
# Package version within this release version.
release: 1
# Section.
section: default
# Priority.
priority: optional
# GoReleaser will automatically add the binaries here
bindir: /opt/openziti/bin
# Contents to add to the package.
contents:
- src: /opt/openziti/bin/zrok
dst: /usr/bin/zrok
type: "symlink"
- package_name: zrok-share
id: zrok-share
vendor: NetFoundry
homepage: https://zrok.io/
maintainer: support@zrok.io
description: |-
This package provides zrok-share.service. To enable, edit the "/opt/openziti/etc/zrok/zrok-share.env" file with the
desired target for sharing, and run "systemctl enable --now zrok-share.service".
license: Apache 2.0
# do not bundle the built binaries, only supporting files
meta: true
# Formats to be generated.
formats:
- deb
- rpm
# {{ .ConventionalFileName }} satisfies the RPM name convention.
file_name_template: "{{ .ConventionalFileName }}"
# Umask to be used on files without explicit mode set. (overridable)
umask: 0o002
# Package version within this release version.
release: 1
# Section.
section: default
# Priority.
priority: optional
# GoReleaser will automatically add the binaries here
dependencies:
- zrok
# this allows users to satisfy the requirement for jq another way, not with the package manager, e.g.
# apt install --no-recommends zrok-share
recommends:
- jq
overrides:
# yum and dnf do not automatically install "weak deps" aka "recommends", so we need to add them as a dependency
rpm:
dependencies:
- zrok
- jq
# Contents to add to the package.
contents:
- dst: /lib/systemd/system/
src: ./nfpm/zrok-share.service
- dst: /opt/openziti/etc/zrok
type: dir
file_info:
mode: 0755
- dst: /opt/openziti/bin/
src: ./nfpm/zrok-share.bash
file_info:
mode: 0755
- dst: /opt/openziti/bin/
src: ./nfpm/zrok-enable.bash
file_info:
mode: 0755
- dst: /opt/openziti/etc/zrok/
src: ./nfpm/zrok-share.env
type: config|noreplace
- dst: /opt/openziti/etc/zrok/
src: ./etc/caddy/multiple_upstream.Caddyfile
type: config|noreplace

View File

@ -1,4 +1,38 @@
# v0.4.8
# CHANGELOG
## v0.4.15
CHANGE: Updated the code signing and notarization process for macos binaries. The previous release process used the `gon` utility to handle both code signing and notarization. Apple changed the requirements and the `gon` utility no longer properly functions as of 2023-11-01. The `goreleaser` process has been adjusted to use the `notarytool` utility that ships with XCode to sign and notarize the binary (https://github.com/openziti/zrok/issues/435)
## v0.4.14
FEATURE: `zrok` Drives "Phase 1" (`p1`) functionality included in this release. This includes new `--backend-mode drive`, which accepts a folder path as a target. A `drive` share can be mounted as a network drive on Windows, macOS, and Linux, allowing full read/write access from all applications on those systems (https://github.com/openziti/zrok/issues/218) Subsequent releases will address CLI use cases and provide further refinements to the overall approach.
FEATURE: Docker Compose project for a reserved public share in docker/compose/zrok-public-reserved/compose.yml is described in the [public share guide](https://docs.zrok.io/docs/guides/docker-share/docker_public_share_guide/).
## v0.4.13
FIX: Update to Homebrew automation to properly integrate with the latest version of the Homebrew release process.
## v0.4.12
FIX: The `zrok reserve` command was not properly recording the reserved share status of the shares that it created, preventing the `zrok release` command from properly releasing them (https://github.com/openziti/zrok/issues/427) If a user encounters reserved shares that cannot be released with the `zrok release` command, they can be deleted through the web console.
## v0.4.11
FEATURE: The `zrok reserve` command now incorporates the `--json-output|-j` flag, which outputs the reservation details as JSON, rather than as human-consumable log messages. Other commands will produce similar output in the future (https://github.com/openziti/zrok/issues/422)
FIX: Include `--oauth-provider` and associated flags for the `zrok reserve` command, allowing reserved shares to specify OAuth authentication (https://github.com/openziti/zrok/issues/421)
## v0.4.10
CHANGE: The public frontend configuration has been bumped from `v: 2` to `v: 3`. The `redirect_host`, `redirect_port` and `redirect_http_only` parameters have been removed. These three configuration options have been replaced with `bind_address`, `redirect_url` and `cookie_domain`. See the OAuth configuration guide at `docs/guides/self-hosting/oauth/configuring-oauth.md` for more details (https://github.com/openziti/zrok/issues/411)
## v0.4.9
FIX: Remove extraneous share token prepended to OAuth frontend redirect.
## v0.4.8
FEATURE: The `sdk` package now includes a `sdk.Overview` function, which returns a complete description of the account attached to the enabled environment. Useful for inventorying the deployed shares and environments (https://github.com/openziti/zrok/issues/407)
@ -12,13 +46,13 @@ CHANGE: Improvements to email invitation sent in response to `zrok invite` to co
CHANGE: Added warning message after `zrok invite` submit directing the user to check their "spam" folder if they do not receive the invite message.
# v0.4.7
## v0.4.7
FEATURE: OAuth authentication with the ability to restrict authenticated users to specified domains for `zrok share public`. Supports both Google and GitHub authentication in this version. More authentication providers, and extensibility to come in future `zrok` releases. See the OAuth configuration guide at `docs/guides/self-hosting/oauth/configuring-oauth.md` for details (https://github.com/openziti/zrok/issues/45, https://github.com/openziti/zrok/issues/404)
CHANGE: `--basic-auth` realm now presented as the share token rather than as `zrok` in `publicProxy` frontend implementation
# v0.4.6
## v0.4.6
FEATURE: New `--backend-mode caddy`, which pre-processes a `Caddyfile` allowing a `bind` statement to work like this: `bind {{ .ZrokBindAddress }}`. Allows development of complicated API gateways and multi-backend shares, while maintaining the simple, ephemeral sharing model provided by `zrok` (https://github.com/openziti/zrok/issues/391)
@ -30,7 +64,7 @@ CHANGE: Added `FrontendEndponts` to `sdk.Share`, returning selected frontend URL
CHANGE: Added a short alias `-b` for `--backend-mode` to improve CLI ergonomics (https://github.com/openziti/zrok/issues/397)
# v0.4.5
## v0.4.5
FEATURE: New health check endpoint (`/health`), which verifies that the underlying SQL store and metrics repository (InfluxDB, if configured) are operating correctly (https://github.com/openziti/zrok/issues/372)
@ -38,27 +72,27 @@ CHANGE: Updated to golang v1.21.0 and node v18.x
FIX: `zrok admin bootstrap` and `zrok enable` both broken with latest OpenZiti releases (tested with `v0.30.0`); updated to latest OpenZiti golang SDK (https://github.com/openziti/zrok/issues/389)
# v0.4.4
## v0.4.4
FIX: `zrok status`, `zrok enable`, `zrok config`, etc. were all causing a panic when used on systems that had no previous `~/.zrok` directory (https://github.com/openziti/zrok/issues/383)
# v0.4.3
## v0.4.3
FEATURE: New `zrok overview` command, which returns all of the account details as a single JSON structure. See the OpenAPI spec at `specs/zrok.yml` for more details of the `/api/v1/overview` endpoint (https://github.com/openziti/zrok/issues/374)
FEATURE: New `zrok` SDK (https://github.com/openziti/zrok/issues/34). `pastebin` example illustrates basic SDK usage (see `sdk/examples/pastebin/README.md` for details) ((https://github.com/openziti/zrok/issues/379)
# v0.4.2
## v0.4.2
Some days are just like this. `v0.4.2` is a re-do of `v0.4.1`. Trying to get Homebrew working and had a bad release. Hopefully this is the one.
# v0.4.1
## v0.4.1
FEATURE: New `zrok console` command to open the currently configured web console in the local web browser (https://github.com/openziti/zrok/issues/170)
CHANGE: Further tweaks to the release process to automatically get the latest release into Homebrew (https://github.com/openziti/zrok/issues/264)
# v0.4.0
## v0.4.0
FEATURE: New `tcpTunnel` backend mode allowing for private sharing of local TCP sockets with other `zrok` users (https://github.com/openziti/zrok/issues/170)
@ -82,21 +116,21 @@ CHANGE: Updated to latest `github.com/openziti/sdk-golang` (https://github.com/o
FIX: `zrok share reserved --override-endpoint` now works correctly; `--override-endpoint` was being incorrectly ignore previously (https://github.com/openziti/zrok/pull/348)
# v0.3.7
## v0.3.7
FIX: Improved TUI word-wrapping (https://github.com/openziti/zrok/issues/180)
# v0.3.6
## v0.3.6
CHANGE: Additional change to support branch builds (for CI purposes) and additional containerization efforts around k8s.
# v0.3.5
## v0.3.5
CHANGE: `zrok config set apiEndpoint` now validates that the new API endpoint correctly starts with `http://` or `https://` (https://github.com/openziti/zrok/issues/258)
CHANGE: Additional linting to support homebrew (https://github.com/openziti/zrok/issues/264)
# v0.3.4
## v0.3.4
CHANGE: `zrok test endpoint` incorporates `--ziti` mode (and related flags) to allow direct endpoint listening on a Ziti service
@ -104,11 +138,11 @@ CHANGE: `zrok test websocket` command to test websockets, whether over TCP or ov
FIX: Websocket support now functional
# v0.3.3
## v0.3.3
CHANGE: `zrok test loop` has been moved to `zrok test loop public`, making way for additional types of loopback testing tools. The `zrok test endpoint` server now includes an `/echo` endpoint, which provides a simple echo websocket (https://github.com/openziti/zrok/issues/237)
# v0.3.2
## v0.3.2
FEATURE: New docker infrastructure, including `docker-compose.yml` examples (and documentation) illustrating how to deploy `zrok` in `docker`-based environments
@ -123,14 +157,14 @@ FEATURE: `zrok controller validate` and `zrok access public validate` will both
CHANGE: `zrok status` no longer shows secrets (secret token, ziti identity) unless the `--secrets` flag is passed (https://github.com/openziti/zrok/issues/243)
# v0.3.1
## v0.3.1
CHANGE: Incorporate initial docker image build (https://github.com/openziti/zrok/issues/217)
CHANGE: Improve target URL parsing for `zrok share` when using `--backend-mode` proxy (https://github.com/openziti/zrok/issues/211)
New and improved URL handling for proxy backends:
9090 -> http://127.0.0.1:9090
localhost:9090 -> http://127.0.0.1:9090
https://localhost:9090 -> https://localhost:9090
@ -139,11 +173,11 @@ CHANGE: Improve usability of `zrok invite` TUI in low-color environments (https:
CHANGE: Better error responses when `zrok invite` fails due to missing token (https://github.com/openziti/zrok/issues/207)
# v0.3.0
## v0.3.0
CHANGE: Removed some minor web console lint and warnings (https://github.com/openziti/zrok/issues/205)
# v0.3.0-rc6
## v0.3.0-rc6
CHANGE: Better error message when `zrok admin create frontend` runs into a duplicate name collision (https://github.com/openziti/zrok/issues/168)
@ -157,7 +191,7 @@ CHANGE: Prevent multiple `zrok enable` commands from succeeding (https://github.
CHANGE: New `--insecure` flag for `share <public|private|reserved>` commands (https://github.com/openziti/zrok/issues/195)
# v0.3.0-rc5
## v0.3.0-rc5
CHANGE: Improvements to controller log messages to assist in operations (https://github.com/openziti/zrok/issues/186)
@ -165,11 +199,11 @@ CHANGE: `armv7` builds for Linux are now shipped with releases; these builds wer
CHANGE: `zrok config set` now includes a warning when the `apiEndpoint` config is changed and an environment is already enabled; the user will not see the change until `zrok disable` is run. The CLI now includes a `zrok config unset` command (https://github.com/openziti/zrok/issues/188)
# v0.3.0-rc4
## v0.3.0-rc4
CHANGE: Enable notarization for macos binaries (https://github.com/openziti/zrok/issues/92)
# v0.3.0-rc3
## v0.3.0-rc3
> This release increments the configuration version from `1` to `2`. See the note below.
@ -185,7 +219,7 @@ FIX: Fixed log message in `resetPasswordRequest.go` (https://github.com/openziti
FIX: Fixed `-v` (verbose mode) on in TUI-based `zrok share` and `zrok access` (https://github.com/openziti/zrok/issues/174)
# v0.3.0-rc2
## v0.3.0-rc2
FEATURE: Allow users to reset their password (https://github.com/openziti/zrok/issues/65)
@ -199,16 +233,16 @@ FIX: Fixed PostgreSQL migration issue where sequences got reset and resulted in
FIX: Remove `frontend` instances when `zrok disable`-ing an environment containing them (https://github.com/openziti/zrok/issues/171)
# v0.3.x Series
## v0.3.x Series
The `v0.2` series was a _proof-of-concept_ implementation for the overall `zrok` architecture and the concept.
`v0.3` is a massive elaboration of the concept, pivoting it from being a simple ephemeral reverse proxy solution, to being the beginnings of a comprehensive sharing platform, complete with public and private sharing (built on top of OpenZiti).
`v0.3` is a massive elaboration of the concept, pivoting it from being a simple ephemeral reverse proxy solution, to being the beginnings of a comprehensive sharing platform, complete with public and private sharing (built on top of OpenZiti).
`v0.3.0` includes the minimal functionality required to produce an early, preview version of the elaborated `zrok` concept, suitable for both production use at `zrok.io`, and also suitable for private self-hosting.
From `v0.3.0` forward, we will begin tracking notable changes in this document.
# v0.2.18
## v0.2.18
* DEFECT: Token generation has been improved to use an alphabet consisting of `[a-zA-Z0-9]`. Service token generation continues to use a case-insensitive alphabet consisting of `[a-z0-9]` to be DNS-safe.

View File

@ -20,7 +20,37 @@ You can be up and sharing using the `zrok.io` service in minutes. Here is a syno
### And then... sharing...
* `zrok share` to share resources immediately, simply and securely
Easily share private network resources with public internet users, securely, without having to alter any of your local network configuration:
```
$ zrok share public localhost:8080
```
![zrok share public](docs/images/zrok_share_public.png)
```
$ curl -s https://dslno640nct4.share.zrok.io | head
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#000000"/>
<meta name="description" content="zrok ui"/>
<link rel="preconnect" href="https://fonts.googleapis.com">
```
Share "network drives" with public and private users running on Windows, macOS, or Linux systems:
```
$ zrok share public --backend-mode drive ~/Repos/zrok
```
![zrok share public -b drive](docs/images/zrok_share_public_drive.png)
Mounting and working with shared drives is simple, and works with any applications on the end users' systems:
![mounted zrok drive](docs/images/zrok_share_public_drive_explorer.png)
See the [Concepts and Getting Started Guide](https://docs.zrok.io/docs/getting-started) for a full overview.
@ -70,6 +100,14 @@ The single `zrok` binary contains everything you need to operate `zrok` environm
See the [Self-Hosting Guide](https://docs.zrok.io/docs/guides/self-hosting/self_hosting_guide/) for details on getting your own `zrok` service instance running.
## zrok Office Hours
We maintain a growing playlist of videos focusing on various aspects of `zrok`. This includes the "office hours" series, which are longer-format videos digging into the implementation of `zrok` and showcasing some of the latest features and capabilities:
[![zrok Office Hours](https://img.youtube.com/vi/Edqv7yRmXb0/0.jpg)](https://www.youtube.com/watch?v=Edqv7yRmXb0&list=PLMUj_5fklasLuM6XiCNqwAFBuZD1t2lO2)
## Building
If you are interested in building `zrok` for yourself instead of using a released package, please refer to [BUILD.md](./BUILD.md)

17
RELEASING.md Normal file
View File

@ -0,0 +1,17 @@
# Releasing zrok
## Manual Steps
1. Create a semver Git tag on main starting with a 'v' character.
1. Push the tag to GitHub.
1. Wait for automated steps to complete.
1. In GitHub Releases, edit the draft release as needed and finalize.
## Automated Steps
1. The Release workflow is triggered by creating the Git tag and
1. uploads Linux packages to Artifactory and
1. drafts a release in GitHub Releases.
1. The Publish Container Images workflow is triggered by the Release event and
1. pushes Docker images to Docker Hub.

View File

@ -1,14 +0,0 @@
source = ["dist/zrok-amd64_darwin_amd64_v1/zrok"]
bundle_id = "io.zrok.zrok"
apple_id {
password = "@env:AC_PASSWORD"
}
sign {
application_identity = "Developer ID Application: NetFoundry Inc"
}
zip {
output_path = "dist/zrok-amd64_darwin_amd64_v1/zrok.zip"
}

View File

@ -1,14 +0,0 @@
source = ["dist/zrok-arm64_darwin_arm64/zrok"]
bundle_id = "io.zrok.zrok"
apple_id {
password = "@env:AC_PASSWORD"
}
sign {
application_identity = "Developer ID Application: NetFoundry Inc"
}
zip {
output_path = "dist/zrok-arm64_darwin_arm64/zrok.zip"
}

View File

@ -173,7 +173,7 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
}()
if cmd.headless {
logrus.Infof("access the zrok share at the followind endpoint: %v", endpointUrl.String())
logrus.Infof("access the zrok share at the following endpoint: %v", endpointUrl.String())
for {
select {
case req := <-requests:

View File

@ -1,12 +1,15 @@
package main
import (
"encoding/json"
"fmt"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/sdk/golang/sdk"
"github.com/openziti/zrok/tui"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"time"
"slices"
)
func init() {
@ -14,10 +17,14 @@ func init() {
}
type reserveCommand struct {
basicAuth []string
frontendSelection []string
backendMode string
cmd *cobra.Command
basicAuth []string
frontendSelection []string
backendMode string
jsonOutput bool
oauthProvider string
oauthEmailDomains []string
oauthCheckInterval time.Duration
cmd *cobra.Command
}
func newReserveCommand() *reserveCommand {
@ -27,17 +34,26 @@ func newReserveCommand() *reserveCommand {
Args: cobra.ExactArgs(2),
}
command := &reserveCommand{cmd: cmd}
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, <tcpTunnel, udpTunnel>, caddy}")
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel)")
cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share")
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
cmd.Flags().StringArrayVar(&command.oauthEmailDomains, "oauth-email-domains", []string{}, "Allow only these email domains to authenticate via OAuth")
cmd.Flags().DurationVar(&command.oauthCheckInterval, "oauth-check-interval", 3*time.Hour, "Maximum lifetime for OAuth authentication; reauthenticate after expiry")
cmd.MarkFlagsMutuallyExclusive("basic-auth", "oauth-provider")
cmd.Run = command.run
return command
}
func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
shareMode := sdk.ShareMode(args[0])
privateOnlyModes := []string{"tcpTunnel", "udpTunnel"}
if shareMode != sdk.PublicShareMode && shareMode != sdk.PrivateShareMode {
tui.Error("invalid sharing mode; expecting 'public' or 'private'", nil)
} else if shareMode == sdk.PublicShareMode && slices.Contains(privateOnlyModes, cmd.backendMode) {
tui.Error(fmt.Sprintf("invalid sharing mode for a %s share: %s", sdk.PublicShareMode, cmd.backendMode), nil)
}
var target string
@ -45,10 +61,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
case "proxy":
v, err := parseUrl(args[1])
if err != nil {
if !panicInstead {
tui.Error("invalid target endpoint URL", err)
}
panic(err)
tui.Error("invalid target endpoint URL", err)
}
target = v
@ -64,16 +77,16 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
case "caddy":
target = args[1]
case "drive":
target = args[1]
default:
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy}", cmd.backendMode), nil)
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil)
}
env, err := environment.LoadRoot()
if err != nil {
if !panicInstead {
tui.Error("error loading environment", err)
}
panic(err)
tui.Error("error loading environment", err)
}
if !env.IsEnabled() {
@ -81,6 +94,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
}
req := &sdk.ShareRequest{
Reserved: true,
BackendMode: sdk.BackendMode(cmd.backendMode),
ShareMode: shareMode,
BasicAuth: cmd.basicAuth,
@ -89,16 +103,29 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
if shareMode == sdk.PublicShareMode {
req.Frontends = cmd.frontendSelection
}
if cmd.oauthProvider != "" {
if shareMode != sdk.PublicShareMode {
tui.Error("--oauth-provider only supported for public shares", nil)
}
req.OauthProvider = cmd.oauthProvider
req.OauthEmailDomains = cmd.oauthEmailDomains
req.OauthAuthorizationCheckInterval = cmd.oauthCheckInterval
}
shr, err := sdk.CreateShare(env, req)
if err != nil {
if !panicInstead {
tui.Error("unable to create share", err)
}
panic(err)
tui.Error("unable to create share", err)
}
logrus.Infof("your reserved share token is '%v'", shr.Token)
for _, fpe := range shr.FrontendEndpoints {
logrus.Infof("reserved frontend endpoint: %v", fpe)
if !cmd.jsonOutput {
logrus.Infof("your reserved share token is '%v'", shr.Token)
for _, fpe := range shr.FrontendEndpoints {
logrus.Infof("reserved frontend endpoint: %v", fpe)
}
} else {
out, err := json.Marshal(shr)
if err != nil {
tui.Error("error emitting JSON", err)
}
fmt.Println(string(out))
}
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/drive"
"github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/endpoints/tcpTunnel"
"github.com/openziti/zrok/endpoints/udpTunnel"
@ -72,8 +73,11 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
target = args[0]
cmd.headless = true
case "drive":
target = args[0]
default:
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy}", cmd.backendMode), nil)
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil)
}
root, err := environment.LoadRoot()
@ -238,6 +242,28 @@ func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
}
}()
case "drive":
cfg := &drive.BackendConfig{
IdentityPath: zif,
DriveRoot: target,
ShrToken: shr.Token,
Requests: requests,
}
be, err := drive.NewBackend(cfg)
if err != nil {
if !panicInstead {
tui.Error("error creating drive backend", err)
}
panic(err)
}
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running drive backend: %v", err)
}
}()
default:
tui.Error("invalid backend mode", nil)
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/openziti/zrok/endpoints"
drive "github.com/openziti/zrok/endpoints/drive"
"github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/environment/env_core"
@ -42,7 +43,7 @@ func newSharePublicCommand() *sharePublicCommand {
}
command := &sharePublicCommand{cmd: cmd}
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, caddy}")
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode {proxy, web, caddy, drive}")
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
cmd.Flags().BoolVar(&command.insecure, "insecure", false, "Enable insecure TLS certificate validation for <target>")
@ -77,8 +78,11 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
target = args[0]
cmd.headless = true
case "drive":
target = args[0]
default:
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web}", cmd.backendMode), nil)
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, caddy, drive}", cmd.backendMode), nil)
}
root, err := environment.LoadRoot()
@ -204,6 +208,28 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
}
}()
case "drive":
cfg := &drive.BackendConfig{
IdentityPath: zif,
DriveRoot: target,
ShrToken: shr.Token,
Requests: requests,
}
be, err := drive.NewBackend(cfg)
if err != nil {
if !panicInstead {
tui.Error("error creating drive backend", err)
}
panic(err)
}
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running drive backend: %v", err)
}
}()
default:
tui.Error("invalid backend mode", nil)
}

View File

@ -5,6 +5,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/drive"
"github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/endpoints/tcpTunnel"
"github.com/openziti/zrok/endpoints/udpTunnel"
@ -123,7 +124,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
proxy.SetCaddyLoggingWriter(mdl)
}
requestsChan := make(chan *endpoints.Request, 1024)
requests := make(chan *endpoints.Request, 1024)
switch resp.Payload.BackendMode {
case "proxy":
cfg := &proxy.BackendConfig{
@ -131,7 +132,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
EndpointAddress: target,
ShrToken: shrToken,
Insecure: cmd.insecure,
Requests: requestsChan,
Requests: requests,
}
be, err := proxy.NewBackend(cfg)
@ -153,7 +154,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
IdentityPath: zif,
WebRoot: target,
ShrToken: shrToken,
Requests: requestsChan,
Requests: requests,
}
be, err := proxy.NewCaddyWebBackend(cfg)
@ -175,7 +176,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
IdentityPath: zif,
EndpointAddress: target,
ShrToken: shrToken,
RequestsChan: requestsChan,
RequestsChan: requests,
}
be, err := tcpTunnel.NewBackend(cfg)
@ -197,7 +198,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
IdentityPath: zif,
EndpointAddress: target,
ShrToken: shrToken,
RequestsChan: requestsChan,
RequestsChan: requests,
}
be, err := udpTunnel.NewBackend(cfg)
@ -218,7 +219,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
cfg := &proxy.CaddyfileBackendConfig{
CaddyfilePath: target,
Shr: &sdk.Share{Token: shrToken, FrontendEndpoints: []string{resp.Payload.FrontendEndpoint}},
Requests: requestsChan,
Requests: requests,
}
be, err := proxy.NewCaddyfileBackend(cfg)
@ -235,6 +236,28 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
}
}()
case "drive":
cfg := &drive.BackendConfig{
IdentityPath: zif,
DriveRoot: target,
ShrToken: shrToken,
Requests: requests,
}
be, err := drive.NewBackend(cfg)
if err != nil {
if !panicInstead {
tui.Error("error creating drive backend", err)
}
panic(err)
}
go func() {
if err := be.Run(); err != nil {
logrus.Errorf("error running drive backend: %v", err)
}
}()
default:
tui.Error("invalid backend mode", nil)
}
@ -249,7 +272,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
}
for {
select {
case req := <-requestsChan:
case req := <-requests:
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
}
}
@ -261,7 +284,7 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
go func() {
for {
select {
case req := <-requestsChan:
case req := <-requests:
prg.Send(req)
}
}
@ -271,6 +294,6 @@ func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
tui.Error("An error occurred", err)
}
close(requestsChan)
close(requests)
}
}

View File

@ -19,8 +19,6 @@ func newShareHandler() *shareHandler {
}
func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zrok.Principal) middleware.Responder {
logrus.Info("handling")
trx, err := str.Begin()
if err != nil {
logrus.Errorf("error starting transaction: %v", err)

View File

@ -0,0 +1,3 @@
-- +migrate Up
alter type backend_mode add value 'drive';

View File

@ -0,0 +1,54 @@
-- +migrate Up
alter table shares rename to shares_old;
create table shares (
id integer primary key,
environment_id integer constraint fk_environments_shares references environments on delete cascade,
z_id string not null unique,
token string not null unique,
share_mode string not null,
backend_mode string not null,
frontend_selection string,
frontend_endpoint string,
backend_proxy_endpoint string,
reserved boolean not null default(false),
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')), deleted boolean not null default(false),
constraint chk_z_id check (z_id <> ''),
constraint chk_token check (token <> ''),
constraint chk_share_mode check (share_mode == 'public' or share_mode == 'private'),
constraint chk_backend_mode check (backend_mode == 'proxy' or backend_mode == 'web' or backend_mode == 'tcpTunnel' or backend_mode == 'udpTunnel' or backend_mode == 'caddy' or backend_mode == 'drive')
);
insert into shares select * from shares_old;
drop table shares_old;
alter table frontends rename to frontends_old;
create table frontends (
id integer primary key,
environment_id integer references environments(id),
token varchar(32) not null unique,
z_id varchar(32) not null,
public_name varchar(64) unique,
url_template varchar(1024),
reserved boolean not null default(false),
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
deleted boolean not null default(false),
private_share_id integer references shares(id)
);
insert into frontends select * from frontends_old;
drop table frontends_old;
alter table share_limit_journal rename to share_limit_journal_old;
create table share_limit_journal (
id integer primary key,
share_id integer references shares(id),
rx_bytes bigint not null,
tx_bytes bigint not null,
action limit_action_type not null,
created_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now')),
updated_at datetime not null default(strftime('%Y-%m-%d %H:%M:%f', 'now'))
);
insert into share_limit_journal select * from share_limit_journal_old;
drop table share_limit_journal_old;

View File

@ -1 +1,2 @@
.env
.env
compose.override.yml

View File

@ -1,37 +1,37 @@
version: '3'
services:
zrok-enable-init:
zrok-init:
image: busybox
# matches uid:gid of "nobody" in zrok container image
command: chown -Rc 65534:65534 /mnt/.zrok
user: root
volumes:
- zrok_env:/mnt/.zrok
zrok-enable:
image: docker.io/openziti/zrok
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
depends_on:
zrok-enable-init:
zrok-init:
condition: service_completed_successfully
entrypoint:
- bash
- -c
- -euc
- |
if [[ -s /mnt/.zrok/environment.json ]]; then
echo "INFO: noop: zrok environment is already enabled"
if [[ -n "$(jq '.ziti_identity' ~/.zrok/environment.json 2>/dev/null)" ]]; then
echo "INFO: zrok environment is already enabled"
exit 0
else
zrok config set apiEndpoint ${ZROK_API_ENDPOINT:-https://api.zrok.io}
echo "INFO: running: zrok $$(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
exec zrok $${@}
exec zrok "$${@}"
fi
command: -- enable --headless ${ZROK_ENABLE_TOKEN}
command: -- enable --headless --description "${ZROK_ENVIRONMENT_NAME:-docker private access}" ${ZROK_ENABLE_TOKEN}
volumes:
- zrok_env:/mnt/.zrok
environment:
HOME: /mnt
ZROK_ENABLE_TOKEN:
ZROK_API_ENDPOINT: ${ZROK_API_ENDPOINT:-https://api.zrok.io/}
zrok-private-access:
image: docker.io/openziti/zrok
zrok-access:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
command: access private --headless --bind 0.0.0.0:9191 ${ZROK_ACCESS_TOKEN}
depends_on:
zrok-enable:
@ -43,12 +43,11 @@ services:
environment:
HOME: /mnt
PFXLOG_NO_JSON: "true"
ZROK_ACCESS_TOKEN:
# alternatively, access the zrok private access proxy from another container
demo-client:
depends_on:
- zrok-private-access
- zrok-access
image: busybox
entrypoint:
- sh
@ -56,7 +55,7 @@ services:
- |
while true; do
echo 'INFO: trying wget';
wget -q -O - http://zrok-private-access:9191/ip;
wget -q -O - http://zrok-access:9191/ip;
sleep 3;
done

View File

@ -1,38 +1,38 @@
version: '3'
services:
zrok-enable-init:
zrok-init:
image: busybox
# matches uid:gid of "nobody" in zrok container image
command: chown -Rc 65534:65534 /mnt/.zrok
user: root
volumes:
- zrok_env:/mnt/.zrok
zrok-enable:
image: docker.io/openziti/zrok
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
depends_on:
zrok-enable-init:
zrok-init:
condition: service_completed_successfully
entrypoint:
- bash
- -c
- -euc
- |
if [[ -s /mnt/.zrok/environment.json ]]; then
echo "INFO: noop: zrok environment is already enabled"
if [[ -n "$(jq '.ziti_identity' ~/.zrok/environment.json 2>/dev/null)" ]]; then
echo "INFO: zrok environment is already enabled"
exit 0
else
zrok config set apiEndpoint ${ZROK_API_ENDPOINT:-https://api.zrok.io}
echo "INFO: running: zrok $$(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
exec zrok $${@}
exec zrok "$${@}"
fi
command: -- enable --headless ${ZROK_ENABLE_TOKEN}
command: -- enable --headless --description "${ZROK_ENVIRONMENT_NAME:-docker private share}" ${ZROK_ENABLE_TOKEN}
volumes:
- zrok_env:/mnt/.zrok
environment:
HOME: /mnt
ZROK_ENABLE_TOKEN:
ZROK_API_ENDPOINT: ${ZROK_API_ENDPOINT:-https://api.zrok.io/}
zrok-public-share:
image: docker.io/openziti/zrok
command: share public --headless http://zrok-test:9090
zrok-share:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
command: share private --headless --backend-mode proxy ${ZROK_TARGET:-http://zrok-test:9090/}
depends_on:
zrok-enable:
condition: service_completed_successfully
@ -44,10 +44,8 @@ services:
# demo servers you can share with zrok
zrok-test:
image: docker.io/openziti/zrok
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
command: test endpoint --address 0.0.0.0 # 9090
httpbin-test:
image: mccutchen/go-httpbin # 8080/tcp
volumes:
zrok_env:

View File

@ -1,53 +0,0 @@
version: '3'
services:
zrok-enable-init:
image: busybox
# matches uid:gid of "nobody" in zrok container image
command: chown -Rc 65534:65534 /mnt/.zrok
user: root
volumes:
- zrok_env:/mnt/.zrok
zrok-enable:
image: docker.io/openziti/zrok
depends_on:
zrok-enable-init:
condition: service_completed_successfully
entrypoint:
- bash
- -c
- |
if [[ -s /mnt/.zrok/environment.json ]]; then
echo "INFO: noop: zrok environment is already enabled"
exit 0
else
echo "INFO: running: zrok $$(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
exec zrok $${@}
fi
command: -- enable --headless ${ZROK_ENABLE_TOKEN}
volumes:
- zrok_env:/mnt/.zrok
environment:
HOME: /mnt
ZROK_ENABLE_TOKEN:
ZROK_API_ENDPOINT: ${ZROK_API_ENDPOINT:-https://api.zrok.io/}
zrok-private-share:
image: docker.io/openziti/zrok
command: share private --headless http://zrok-test:9090
depends_on:
zrok-enable:
condition: service_completed_successfully
volumes:
- zrok_env:/mnt/.zrok
environment:
HOME: /mnt
PFXLOG_NO_JSON: "true"
# demo servers you can share with zrok
zrok-test:
image: docker.io/openziti/zrok
command: test endpoint --address 0.0.0.0 # 9090
httpbin-test:
image: mccutchen/go-httpbin # 8080/tcp
volumes:
zrok_env:

View File

@ -0,0 +1,173 @@
services:
# create Caddyfile
zrok-caddyfile:
image: busybox
# create Caddyfile
entrypoint:
- sh
- -euc
- |
ZROK_UPSTREAM_URL="${ZROK_TARGET:-http://zrok-test:9090}"
ZROK_UPSTREAM_HOST="$(echo $${ZROK_UPSTREAM_URL}|sed -E 's#^https?://([^/:]+).*#\1#')"
mkdir -p /mnt/.zrok
cat <<CADDYFILE >| /mnt/.zrok/Caddyfile
{
# GET /config/ and POST /load on this API to reload Caddy config
admin 0.0.0.0:2019
}
http:// {
bind {{ .ZrokBindAddress }}
handle_path /zrok-test/* {
reverse_proxy http://zrok-test:9090 {
header_up Host zrok-test
}
}
handle_path /zrok-static/* {
root * /mnt/.zrok/html
file_server browse
}
reverse_proxy /* $${ZROK_UPSTREAM_URL} {
header_up Host $${ZROK_UPSTREAM_HOST}
}
}
CADDYFILE
user: root
volumes:
- zrok_env:/mnt
# set file ownership
zrok-init:
image: busybox
depends_on:
zrok-caddyfile:
condition: service_completed_successfully
# matches uid:gid of "nobody" in zrok container image
command: chown -Rc 65534:65534 /mnt/
user: root
volumes:
- zrok_env:/mnt
# enable zrok environment
zrok-enable:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
depends_on:
zrok-init:
condition: service_completed_successfully
entrypoint:
- bash
- -euc
- |
if [[ -s ~/.zrok/environment.json ]]; then
ZITI_ID="$(jq '.ziti_identity' ~/.zrok/environment.json 2>/dev/null)"
if [[ -z "$${ZITI_ID}" || "$${ZITI_ID}" == null ]]; then
echo "ERROR: invalid environment; consider a reset with 'docker compose down --volumes'" >&2
exit 1
else
echo "INFO: zrok environment is already enabled"
exit 0
fi
else
if [[ -z "${ZROK_ENABLE_TOKEN}" ]]; then
echo "ERROR: ZROK_ENABLE_TOKEN is not defined" >&2
exit 1
else
zrok config set apiEndpoint ${ZROK_API_ENDPOINT:-https://api.zrok.io}
echo "INFO: running: zrok $(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
exec zrok "$${@}"
fi
fi
command: -- enable --headless --description "${ZROK_ENVIRONMENT_NAME:-docker reserved public share}" ${ZROK_ENABLE_TOKEN}
volumes:
- zrok_env:/mnt
environment:
HOME: /mnt
# reserve zrok frontend url for the zrok backend config
zrok-reserve:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
entrypoint:
- bash
- -euc
- |
if [[ -s ~/.zrok/reserved.json ]]; then
ZROK_RESERVED_TOKEN="$(jq '.token' ~/.zrok/reserved.json 2>/dev/null)"
if [[ -z "$${ZROK_RESERVED_TOKEN}" || "$${ZROK_RESERVED_TOKEN}" == null ]]; then
echo "ERROR: invalid reserved.json: $(jq -c . ~/.zrok/reserved.json)" >&2
exit 1
else
echo "INFO: zrok backend is already reserved: $${ZROK_RESERVED_TOKEN}"
exit 0
fi
else
set -o pipefail
ZROK_CMD="reserve public --json-output"
if [[ -n "${ZROK_SHARE_OPTS:-}" ]]; then
ZROK_CMD+=" ${ZROK_SHARE_OPTS}"
fi
if [[ -n "${ZROK_OAUTH_PROVIDER:-}" ]]; then
ZROK_CMD+=" --oauth-provider ${ZROK_OAUTH_PROVIDER}"
fi
if [[ -n "${ZROK_BACKEND_MODE:-}" && "${ZROK_BACKEND_MODE}" != caddy ]]; then
ZROK_CMD+=" --backend-mode ${ZROK_BACKEND_MODE} ${ZROK_TARGET:-http://zrok-test:9090}"
else
ZROK_CMD+=" --backend-mode caddy /mnt/.zrok/Caddyfile"
fi
echo "INFO: running: zrok $${ZROK_CMD}"
zrok $${ZROK_CMD} | jq -rc | tee ~/.zrok/reserved.json
fi
depends_on:
zrok-enable:
condition: service_completed_successfully
volumes:
- zrok_env:/mnt
environment:
HOME: /mnt
# start share on reserved public frontend url
zrok-share:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
entrypoint:
- bash
- -euc
- |
if ! [[ -s ~/.zrok/reserved.json ]]; then
echo "ERROR: empty or missing reserved.json" >&2
exit 1
else
ZROK_PUBLIC_URLS=$(jq -cr '.frontend_endpoints' ~/.zrok/reserved.json 2>/dev/null)
if [[ -z "$${ZROK_PUBLIC_URLS}" || "$${ZROK_PUBLIC_URLS}" == null ]]; then
echo "ERROR: frontend endpoints not defined" >&2
exit 1
else
echo "INFO: zrok public URLs: $${ZROK_PUBLIC_URLS}"
fi
ZROK_RESERVED_TOKEN=$(jq -r '.token' ~/.zrok/reserved.json 2>/dev/null)
if [[ -z "$${ZROK_RESERVED_TOKEN}" && "$${ZROK_RESERVED_TOKEN}" == null ]]; then
echo "ERROR: zrok reservation token not defined" >&2
exit 1
else
echo "INFO: zrok reservation token: $${ZROK_RESERVED_TOKEN}"
fi
echo "INFO: running: zrok $${@} $${ZROK_RESERVED_TOKEN}"
exec zrok "$${@}" $${ZROK_RESERVED_TOKEN}
fi
command: -- share reserved --headless
depends_on:
zrok-reserve:
condition: service_completed_successfully
volumes:
- zrok_env:/mnt
ports:
- 127.0.0.1:2019:2019
environment:
HOME: /mnt
PFXLOG_NO_JSON: "true"
# demo server
zrok-test:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
command: test endpoint --address 0.0.0.0 # 9090
volumes:
zrok_env:

View File

@ -0,0 +1,69 @@
services:
# set file ownership
zrok-init:
image: busybox
# matches uid:gid of "nobody" in zrok container image
command: chown -Rc 65534:65534 /mnt/.zrok
user: root
volumes:
- zrok_env:/mnt/.zrok
# enable zrok environment
zrok-enable:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
depends_on:
zrok-init:
condition: service_completed_successfully
entrypoint:
- bash
- -euc
- |
if [[ -n "$(jq '.ziti_identity' ~/.zrok/environment.json 2>/dev/null)" ]]; then
echo "INFO: zrok environment is already enabled"
exit 0
else
zrok config set apiEndpoint ${ZROK_API_ENDPOINT:-https://api.zrok.io}
echo "INFO: running: zrok $$(sed -E "s/${ZROK_ENABLE_TOKEN}/************/" <<< $${@})"
exec zrok "$${@}"
fi
command: -- enable --headless --description "${ZROK_ENVIRONMENT_NAME:-docker temp public share}" ${ZROK_ENABLE_TOKEN}
volumes:
- zrok_env:/mnt/.zrok
environment:
HOME: /mnt
# start share on temporary public frontend url
zrok-share:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
entrypoint:
- bash
- -euc
- |
set -o pipefail
ZROK_CMD="share public --headless"
if [[ -n "${ZROK_SHARE_OPTS:-}" ]]; then
ZROK_CMD+=" ${ZROK_SHARE_OPTS}"
fi
if [[ -n "${ZROK_OAUTH_PROVIDER:-}" ]]; then
ZROK_CMD+=" --oauth-provider ${ZROK_OAUTH_PROVIDER}"
fi
ZROK_CMD+=" --backend-mode proxy ${ZROK_TARGET:-http://zrok-test:9090/}"
echo "INFO: running: zrok $${ZROK_CMD}"
exec zrok $${ZROK_CMD}
depends_on:
zrok-enable:
condition: service_completed_successfully
volumes:
- zrok_env:/mnt/.zrok
environment:
HOME: /mnt
PFXLOG_NO_JSON: "true"
# demo servers you can share with zrok
zrok-test:
image: ${ZROK_CONTAINER_IMAGE:-docker.io/openziti/zrok}
command: test endpoint --address 0.0.0.0 # 9090
volumes:
zrok_env:

View File

@ -5,7 +5,7 @@ FROM debian:bullseye-slim
#
ARG TARGETARCH
ARG golang_version=1.19.5
ARG golang_version=1.21.3
ARG go_distribution_file=go${golang_version}.linux-${TARGETARCH}.tar.gz
ARG go_path=/usr/share/go
ARG go_root=/usr/local/go

View File

@ -1,7 +1,8 @@
# this builds docker.io/openziti/zrok
FROM docker.io/openziti/ziti-cli:0.27.9
# This build stage grabs artifacts that are copied into the final image.
# It uses the same base as the final image to maximize docker cache hits.
ARG ZITI_CLI_TAG="0.30.5"
ARG ZITI_CLI_IMAGE="docker.io/openziti/ziti-cli"
# this builds docker.io/openziti/ziti-controller
FROM ${ZITI_CLI_IMAGE}:${ZITI_CLI_TAG}
ARG ARTIFACTS_DIR=./dist
ARG DOCKER_BUILD_DIR=.
@ -19,6 +20,11 @@ LABEL name="openziti/zrok" \
USER root
### install packages (jq introduced in source image in next release 0.30.6)
RUN INSTALL_PKGS="jq" && \
microdnf -y update --setopt=install_weak_deps=0 --setopt=tsflags=nodocs && \
microdnf -y install --setopt=install_weak_deps=0 --setopt=tsflags=nodocs ${INSTALL_PKGS}
### add licenses to this directory
RUN mkdir -p -m0755 /licenses
COPY ./LICENSE /licenses/apache.txt

View File

@ -293,7 +293,7 @@ Usage:
zrok share public <target> [flags]
Flags:
--backend-mode string The backend mode {proxy, web} (default "proxy")
--backend-mode string The backend mode {proxy, web, caddy, drive} (default "proxy")
--basic-auth stringArray Basic authentication users (<username:password>,...)
--frontends stringArray Selected frontends to use for the share (default [public])
--headless Disable TUI and run headless

View File

@ -24,7 +24,7 @@ First, let's create the private share.
1. Make a folder on your computer to use as a Docker Compose project for your zrok private share.
1. In your terminal, change directory to your newly-created project folder.
1. Download [the zrok-private-share Docker Compose project file](pathname:///zrok-private-share/docker-compose.yml) into your new project folder and make sure it's named `docker-compose.yml`.
1. Download [the zrok-private-share Docker Compose project file](pathname:///zrok-private-share/compose.yml) into your new project folder and make sure it's named `compose.yml`.
1. Copy your zrok environment token from the zrok web console to your clipboard and paste it in a file named `.env` in the same folder like this:
```bash
@ -59,7 +59,7 @@ Now that we have a private share we can access it with zrok running in Docker. N
1. Make a folder on your computer to use as a Docker Compose project for your zrok private access.
1. In your terminal, change directory to your newly-created project folder.
1. Download [the zrok-private-access Docker Compose project file](pathname:///zrok-private-access/docker-compose.yml) into your new project folder and make sure it's named `docker-compose.yml`.
1. Download [the zrok-private-access Docker Compose project file](pathname:///zrok-private-access/compose.yml) into your new project folder and make sure it's named `compose.yml`.
1. Copy your zrok environment token from the zrok web console to your clipboard and paste it in a file named `.env` in the same folder like this:
```bash

View File

@ -5,7 +5,7 @@ sidebar_label: Public Share
# Docker Public Share
With zrok, you can publicly share a server app that's running in another Docker container, or any server that's reachable by the zrok container.
With zrok and Docker, you can publicly share a web server that's running in a local container or anywhere that's reachable by the zrok container. The share can be reached through a public URL thats temporary or reserved (reusable).
## Walkthrough Video
@ -15,61 +15,137 @@ With zrok, you can publicly share a server app that's running in another Docker
To follow this guide you will need [Docker](https://docs.docker.com/get-docker/) and [the Docker Compose plugin](https://docs.docker.com/compose/install/) for running `docker compose` commands in your terminal.
## Public Share with Docker Compose
## Temporary or Reserved Public Share
A temporary public share is a great way to share a web server running in a container with someone else for a short time. A reserved public share is a great way to share a reliable web server running in a container with someone else for a long time.
1. Make a folder on your computer to use as a Docker Compose project for your zrok public share.
1. In your terminal, change directory to your newly-created project folder.
1. Download [the zrok-public-share Docker Compose project file](pathname:///zrok-public-share/docker-compose.yml) into your new project folder.
1. In your terminal, change directory to the newly-created project folder.
1. Download either [the temporary public share project file](pathname:///zrok-public-share/compose.yml) or [the reserved public share project file](pathname:///zrok-public-reserved/compose.yml) into the project folder.
1. Copy your zrok environment token from the zrok web console to your clipboard and paste it in a file named `.env` in the same folder like this:
```bash
# file name ".env"
ZROK_ENABLE_TOKEN="8UL9-48rN0ua"
```bash title=".env"
ZROK_ENABLE_TOKEN="8UL9-48rN0ua"
```
1. Set the zrok API endpoint if self-hosting zrok. Skip this if using zrok.io.
```bash title=".env"
ZROK_API_ENDPOINT="https://zrok.example.com"
```
1. Run the Compose project to start sharing the built-in demo web server.
```bash
docker compose up --detach
```
1. Get the public share URL from the output of the `zrok-share` service or by peeking in the zrok console where the share will be graphed.
```bash
docker compose logs zrok-share
```
```buttonless title="Output"
zrok-public-share-1 | https://w6r1vesearkj.in.zrok.io/
```
This concludes sharing the demo web server. Read on to learn how to pivot to sharing any web server leveraging additional zrok backend modes.
## Proxy Any Web Server
The simplest way to share your web server is to set `ZROK_TARGET` (e.g. `https://example.com`) in the environment of the `docker compose up` command. When you restart the share will auto-configure for that upstream server URL. This applies to both temporary and reserved public shares.
```bash title=".env"
ZROK_TARGET="http://example.com:8080"
```
## Require Authentication
You can require authentication for your public share by setting `ZROK_OAUTH_PROVIDER` to `github` or `google` if you're using our hosted zrok.io, and any OIDC provider you've configured if self-hosting. You can parse the authenticated email address from the request cookie. Read more about the OAuth features in [this blog post](https://blog.openziti.io/the-zrok-oauth-public-frontend). This applies to both temporary and reserved public shares.
```bash title=".env"
ZROK_OAUTH_PROVIDER="github"
```
## Customize Temporary Public Share
1. Create a file `compose.override.yml`. This example demonstrates sharing a static HTML directory `/tmp/html` from the Docker host's filesystem.
```yaml title="compose.override.yml"
services:
zrok-share:
command: share public --headless --backend-mode web /tmp/html
volumes:
- /tmp/html:/tmp/html
```
1. Re-run the project to load the new configuration.
```bash
docker compose up --force-recreate --detach
```
1. Get the new tempoary public share URL for the `zrok-share` container.
```bash
docker compose logs zrok-share
```
```buttonless title="Output"
zrok-public-share-1 | https://w6r1vesearkj.in.zrok.io/
```
1. If you are self-hosting zrok then it's important to set your API endpoint URL too. If you're using the hosted zrok service then you can skip this step.
## Customize Reserved Public Share
```bash
# file name ".env"
ZROK_API_ENDPOINT="https://zrok.example.com"
```
The reserved public share project uses zrok's `caddy` mode. Caddy accepts configuration as a Caddyfile that is mounted into the container ([zrok Caddyfile examples](https://github.com/openziti/zrok/tree/main/etc/caddy)).
1. Run your Compose project to start sharing the built-in demo web server:
1. Create a Caddyfile. This example demonstrates proxying two HTTP servers with a weighted round-robin load balancer.
```bash
docker compose up
```
```console title="Caddyfile"
http:// {
# zrok requires this bind address template
bind {{ .ZrokBindAddress }}
reverse_proxy /* {
to http://httpbin1:8080 http://httpbin2:8080
lb_policy weighted_round_robin 3 2
}
}
```
1. Read the public share URL from the output. One of the last lines is like this:
1. Create a file `compose.override.yml`. This example adds two `httpbin` containers for Caddy load balance, and masks the default Caddyfile with our custom one.
```bash
zrok-public-share-1 | https://w6r1vesearkj.in.zrok.io/
```
```yaml title="compose.override.yml"
services:
httpbin1:
image: mccutchen/go-httpbin # 8080/tcp
httpbin2:
image: mccutchen/go-httpbin # 8080/tcp
zrok-share:
volumes:
- ./Caddyfile:/mnt/.zrok/Caddyfile
```
You can swap in a different server app container instead of the demo server, or you could change the Docker network to "host" and share something running on the Docker host's localhost interface.
1. Re-run the project to load the new configuration.
1. Edit the file `docker-compose.yml`. Replace the following line:
```bash
docker compose up --force-recreate --detach
```
```yaml
command: share public --headless http://zrok-test:9090
```
1. Recall the reserved share URL from the log.
Replace that line with this to start sharing the HTTPBin server app container instead of the zrok test endpoint.
```bash
docker compose logs zrok-share
```
```yaml
command: share public --headless http://httpbin-test:8080
```
```buttonless title="Output"
INFO: zrok public URL: https://88s803f2qvao.in.zrok.io/
```
1. Re-run your project to load the new server configuration.
## Destroy the zrok Environment
```bash
docker-compose up --force-recreate
```
This destroys the Docker volumes containing the zrok environment secrets. The zrok environment can also be destroyed in the web console.
Now you'll have a new public share URL for the `httpbin` API testing server.
1. Run "down" to destroy the Compose project when you're done. Then delete the selected zrok environment by clicking "Actions" in the web console.
```bash
docker compose down --remove-orphans --volumes
```
```bash
docker compose down --volumes
```

View File

@ -49,6 +49,12 @@ server {
}
map $http_upgrade $connection_upgrade {
default keep-alive;
'websocket' upgrade;
'' close;
}
server {
listen 443 ssl;
server_name *.zrok.quigley.com;
@ -65,8 +71,10 @@ server {
proxy_buffers 4 512k;
proxy_buffer_size 256k;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
```

View File

@ -90,23 +90,25 @@ The public frontend configuration includes a new `oauth` section:
```yaml
oauth:
redirect_host: oauth.zrok.io
redirect_port: 28080
redirect_http_only: false
hash_key: "<yourRandomHashKey>"
bind_address: 0.0.0.0:8181
redirect_url: https://oauth.zrok.io
cookie_domain: zrok.io
hash_key: "the quick brown fox jumped over the lazy dog"
providers:
- name: google
client_id: <client-id>
client_secret: <client-secret>
- name: github
client_id: <client-id>
client_secret: <client-secret>
- name: google
client_id: "<client id from google>"
client_secret: "<client secret from google>"
- name: github
client_id: "<client id from github>"
client_secret: "<client secret from github>"
```
The `redirect_host` and `redirect_port` value should correspond with the DNS hostname and port configured as your OAuth frontend.
The `bind_address` parameter determines where the OAuth frontend will bind. Should be in `ip:port` format.
The `redirect_http_only` is useful in development environments where your OAuth frontend is not running behind an HTTPS reverse proxy. Should not be enabled in production environments!
The `redirect_url` parameter determines the base URL where OAuth frontend requests will be redirected.
`cookie_domain` is the domain where authentication cookies should be stored.
`hash_key` is a unique string for your installation that is used to secure the authentication payloads for your public frontend.
@ -118,14 +120,14 @@ Both the `google` and `github` providers accept a `client_id` and `client_secret
With your public frontend configured to support OAuth, you can test this by creating a public share. There are new command line options to support this:
```
```text
$ zrok share public
Error: accepts 1 arg(s), received 0
Usage:
zrok share public <target> [flags]
Flags:
-b, --backend-mode string The backend mode {proxy, web, caddy} (default "proxy")
-b, --backend-mode string The backend mode {proxy, web, caddy, drive} (default "proxy")
--basic-auth stringArray Basic authentication users (<username:password>,...)
--frontends stringArray Selected frontends to use for the share (default [public])
--headless Disable TUI and run headless
@ -148,7 +150,6 @@ The `--oauth-check-interval` flag specifies how frequently the authentication mu
An example public share:
```text
zrok share public --backend-mode web --oauth-provider github --oauth-email-domains zrok.io ~/public
```
$ zrok share public --backend-mode web --oauth-provider github --oauth-email-domains zrok.io ~/public
```

View File

@ -192,14 +192,19 @@ Nice work! The `zrok` controller is fully configured now that you have created t
## Configure the Public Frontend
Create `etc/http-frontend.yml`. This frontend config file has a `host_match` pattern that represents the DNS zone you're using with this instance of zrok. Incoming HTTP requests with a matching `Host` header will be handled by this frontend. You may also specify the interface address where the frontend will listen for public access requests.
Create an http frontend configuration file in `etc/http-frontend.yml`.
```yaml
v: 3
host_match: zrok.quigley.com
address: 0.0.0.0:8080
```
This frontend config file has a `host_match` pattern that represents the DNS zone you're using with this instance of zrok. Incoming HTTP requests with a matching `Host` header will be handled by this frontend. You may also specify the interface address where the frontend will listen for public access requests.
The frontend does not provide server TLS, but you may front the server with a reverse proxy. It is essential the reverse proxy forwards the `Host` header supplied by the viewer. This example will expose the non-TLS listener for the frontend.
```yaml
host_match: zrok.quigley.com
address: 0.0.0.0:8080
```
You can also specify an `oauth` configuration in this file, full details of are found in [OAuth Public Frontend Configuration](oauth/configuring-oauth.md#configuring-your-public-frontend).
## Start Public Frontend

0
docs/images/zrok.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

0
docs/images/zrok_cover.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

0
docs/images/zrok_deployment.drawio Executable file → Normal file
View File

0
docs/images/zrok_deployment.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

0
docs/images/zrok_docs_share.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

0
docs/images/zrok_enable_modal.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

0
docs/images/zrok_frontends_v0.3.drawio Executable file → Normal file
View File

0
docs/images/zrok_frontends_v0.3.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

0
docs/images/zrok_not_found.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

0
docs/images/zrok_registration_success.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

0
docs/images/zrok_reserved_not_found.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

0
docs/images/zrok_share_reserved.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

0
docs/images/zrok_share_web_files.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
docs/images/zrok_share_web_website.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

0
docs/images/zrok_v0.1_overview.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

0
docs/images/zrok_verify.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

0
docs/images/zrok_web_console.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 96 KiB

After

Width:  |  Height:  |  Size: 96 KiB

0
docs/images/zrok_web_console_empty.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

0
docs/images/zrok_web_console_environment_spark.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

0
docs/images/zrok_web_console_explorer_share.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

0
docs/images/zrok_web_console_share_detail.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

0
docs/images/zrok_web_console_share_frontend.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

0
docs/images/zrok_web_login.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

0
docs/images/zrok_web_ui_empty_environment_detail.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

0
docs/images/zrok_web_ui_empty_shares.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

0
docs/images/zrok_web_ui_new_environment.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 68 KiB

0
docs/images/zrok_zoom_to_fit.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,72 @@
package drive
import (
"fmt"
"github.com/openziti/sdk-golang/ziti"
"github.com/openziti/sdk-golang/ziti/edge"
"github.com/openziti/zrok/endpoints"
"github.com/pkg/errors"
"golang.org/x/net/webdav"
"net/http"
"time"
)
type BackendConfig struct {
IdentityPath string
DriveRoot string
ShrToken string
Requests chan *endpoints.Request
}
type Backend struct {
cfg *BackendConfig
listener edge.Listener
handler http.Handler
}
func NewBackend(cfg *BackendConfig) (*Backend, error) {
options := ziti.ListenOptions{
ConnectTimeout: 5 * time.Minute,
MaxConnections: 64,
}
zcfg, err := ziti.NewConfigFromFile(cfg.IdentityPath)
if err != nil {
return nil, errors.Wrap(err, "error loading ziti identity")
}
zctx, err := ziti.NewContext(zcfg)
if err != nil {
return nil, errors.Wrap(err, "error loading ziti context")
}
listener, err := zctx.ListenWithOptions(cfg.ShrToken, &options)
if err != nil {
return nil, err
}
handler := &webdav.Handler{
FileSystem: webdav.Dir(cfg.DriveRoot),
LockSystem: webdav.NewMemLS(),
Logger: func(r *http.Request, err error) {
if cfg.Requests != nil {
cfg.Requests <- &endpoints.Request{
Stamp: time.Now(),
RemoteAddr: fmt.Sprintf("%v", r.Header["X-Real-Ip"]),
Method: r.Method,
Path: r.URL.String(),
}
}
},
}
return &Backend{
cfg: cfg,
listener: listener,
handler: handler,
}, nil
}
func (b *Backend) Run() error {
if err := http.Serve(b.listener, b.handler); err != nil {
return err
}
return nil
}

View File

@ -25,7 +25,6 @@ type BackendConfig struct {
type Backend struct {
cfg *BackendConfig
requests func() int32
listener edge.Listener
handler http.Handler
}
@ -56,7 +55,6 @@ func NewBackend(cfg *BackendConfig) (*Backend, error) {
handler := util.NewProxyHandler(proxy)
return &Backend{
cfg: cfg,
requests: handler.Requests,
listener: listener,
handler: handler,
}, nil
@ -69,10 +67,6 @@ func (b *Backend) Run() error {
return nil
}
func (b *Backend) Requests() func() int32 {
return b.requests
}
func newReverseProxy(cfg *BackendConfig) (*httputil.ReverseProxy, error) {
targetURL, err := url.Parse(cfg.EndpointAddress)
if err != nil {

View File

@ -56,10 +56,6 @@ func (b *CaddyfileBackend) Run() error {
return nil
}
func (b *CaddyfileBackend) Requests() func() int32 {
return nil
}
func preprocessCaddyfile(inF string, shr *sdk.Share) (string, error) {
input, err := os.ReadFile(inF)
if err != nil {

View File

@ -2,15 +2,13 @@ package publicProxy
import (
"context"
"fmt"
"github.com/michaelquigley/cf"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
zhttp "github.com/zitadel/oidc/v2/pkg/http"
"strings"
)
const V = 2
const V = 3
type Config struct {
V int
@ -21,11 +19,11 @@ type Config struct {
}
type OauthConfig struct {
RedirectHost string
RedirectPort int
RedirectHttpOnly bool
HashKey string `cf:"+secret"`
Providers []*OauthProviderConfig
BindAddress string
RedirectUrl string
CookieDomain string
HashKey string `cf:"+secret"`
Providers []*OauthProviderConfig
}
func (oc *OauthConfig) GetProvider(name string) *OauthProviderConfig {
@ -71,6 +69,6 @@ func configureOauthHandlers(ctx context.Context, cfg *Config, tls bool) error {
if err := configureGithubOauth(cfg.Oauth, tls); err != nil {
return err
}
zhttp.StartServer(ctx, fmt.Sprintf("%s:%d", strings.Split(cfg.Address, ":")[0], cfg.Oauth.RedirectPort))
zhttp.StartServer(ctx, cfg.Oauth.BindAddress)
return nil
}

View File

@ -16,7 +16,6 @@ import (
"io"
"net/http"
"net/url"
"strings"
"time"
)
@ -32,12 +31,10 @@ func configureGithubOauth(cfg *OauthConfig, tls bool) error {
return nil
}
clientID := providerCfg.ClientId
callbackPath := "/github/oauth"
redirectUrl := fmt.Sprintf("%s://%s", scheme, cfg.RedirectHost)
rpConfig := &oauth2.Config{
ClientID: clientID,
ClientSecret: providerCfg.ClientSecret,
RedirectURL: fmt.Sprintf("%v:%v%v", redirectUrl, cfg.RedirectPort, callbackPath),
RedirectURL: fmt.Sprintf("%v/github/oauth", cfg.RedirectUrl),
Scopes: []string{"user:email"},
Endpoint: githubOAuth.Endpoint,
}
@ -52,15 +49,7 @@ func configureGithubOauth(cfg *OauthConfig, tls bool) error {
}
key := hash.Sum(nil)
u, err := url.Parse(redirectUrl)
if err != nil {
logrus.Errorf("unable to parse redirect url: %v", err)
return err
}
parts := strings.Split(u.Hostname(), ".")
domain := parts[len(parts)-2] + "." + parts[len(parts)-1]
cookieHandler := zhttp.NewCookieHandler(key, key, zhttp.WithUnsecure(), zhttp.WithDomain(domain))
cookieHandler := zhttp.NewCookieHandler(key, key, zhttp.WithUnsecure(), zhttp.WithDomain(cfg.CookieDomain))
options := []rp.Option{
rp.WithCookieHandler(cookieHandler),
@ -177,10 +166,10 @@ func configureGithubOauth(cfg *OauthConfig, tls bool) error {
authCheckInterval = i
}
SetZrokCookie(w, domain, primaryEmail, tokens.AccessToken, "github", authCheckInterval, key)
SetZrokCookie(w, cfg.CookieDomain, primaryEmail, tokens.AccessToken, "github", authCheckInterval, key)
http.Redirect(w, r, fmt.Sprintf("%s://%s", scheme, token.Claims.(*IntermediateJWT).Host), http.StatusFound)
}
http.Handle(callbackPath, rp.CodeExchangeHandler(getEmail, relyingParty))
http.Handle("/github/oauth", rp.CodeExchangeHandler(getEmail, relyingParty))
return nil
}

View File

@ -16,7 +16,6 @@ import (
"io"
"net/http"
"net/url"
"strings"
"time"
)
@ -33,12 +32,10 @@ func configureGoogleOauth(cfg *OauthConfig, tls bool) error {
}
clientID := providerCfg.ClientId
callbackPath := "/google/oauth"
redirectUrl := fmt.Sprintf("%s://%s", scheme, cfg.RedirectHost)
rpConfig := &oauth2.Config{
ClientID: clientID,
ClientSecret: providerCfg.ClientSecret,
RedirectURL: fmt.Sprintf("%v:%v%v", redirectUrl, cfg.RedirectPort, callbackPath),
RedirectURL: fmt.Sprintf("%v/google/oauth", cfg.RedirectUrl),
Scopes: []string{"https://www.googleapis.com/auth/userinfo.email"},
Endpoint: googleOauth.Endpoint,
}
@ -53,15 +50,7 @@ func configureGoogleOauth(cfg *OauthConfig, tls bool) error {
}
key := hash.Sum(nil)
u, err := url.Parse(redirectUrl)
if err != nil {
logrus.Errorf("unable to parse redirect url: %v", err)
return err
}
parts := strings.Split(u.Hostname(), ".")
domain := parts[len(parts)-2] + "." + parts[len(parts)-1]
cookieHandler := zhttp.NewCookieHandler(key, key, zhttp.WithUnsecure(), zhttp.WithDomain(domain))
cookieHandler := zhttp.NewCookieHandler(key, key, zhttp.WithUnsecure(), zhttp.WithDomain(cfg.CookieDomain))
options := []rp.Option{
rp.WithCookieHandler(cookieHandler),
@ -157,10 +146,10 @@ func configureGoogleOauth(cfg *OauthConfig, tls bool) error {
authCheckInterval = i
}
SetZrokCookie(w, domain, rDat.Email, tokens.AccessToken, "google", authCheckInterval, key)
SetZrokCookie(w, cfg.CookieDomain, rDat.Email, tokens.AccessToken, "google", authCheckInterval, key)
http.Redirect(w, r, fmt.Sprintf("%s://%s", scheme, token.Claims.(*IntermediateJWT).Host), http.StatusFound)
}
http.Handle(callbackPath, rp.CodeExchangeHandler(getEmail, relyingParty))
http.Handle("/google/oauth", rp.CodeExchangeHandler(getEmail, relyingParty))
return nil
}

View File

@ -228,7 +228,7 @@ func authHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Contex
cookie, err := r.Cookie("zrok-access")
if err != nil {
logrus.Errorf("unable to get 'zrok-access' cookie: %v", err)
oauthLoginRequired(w, r, shrToken, pcfg, provider.(string), target, authCheckInterval)
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
return
}
tkn, err := jwt.ParseWithClaims(cookie.Value, &ZrokClaims{}, func(t *jwt.Token) (interface{}, error) {
@ -239,18 +239,18 @@ func authHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Contex
})
if err != nil {
logrus.Errorf("unable to parse jwt: %v", err)
oauthLoginRequired(w, r, shrToken, pcfg, provider.(string), target, authCheckInterval)
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
return
}
claims := tkn.Claims.(*ZrokClaims)
if claims.Provider != provider {
logrus.Error("provider mismatch; restarting auth flow")
oauthLoginRequired(w, r, shrToken, pcfg, provider.(string), target, authCheckInterval)
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
return
}
if claims.AuthorizationCheckInterval != authCheckInterval {
logrus.Error("authorization check interval mismatch; restarting auth flow")
oauthLoginRequired(w, r, shrToken, pcfg, provider.(string), target, authCheckInterval)
oauthLoginRequired(w, r, pcfg.Oauth, provider.(string), target, authCheckInterval)
return
}
if validDomains, found := oauthCfg.(map[string]interface{})["email_domains"]; found {
@ -347,12 +347,8 @@ func basicAuthRequired(w http.ResponseWriter, realm string) {
_, _ = w.Write([]byte("No Authorization\n"))
}
func oauthLoginRequired(w http.ResponseWriter, r *http.Request, shrToken string, pcfg *Config, provider, target string, authCheckInterval time.Duration) {
scheme := "https"
if pcfg.Oauth != nil && pcfg.Oauth.RedirectHttpOnly {
scheme = "http"
}
http.Redirect(w, r, fmt.Sprintf("%s://%s.%s:%d/%s/login?targethost=%s&checkInterval=%s", scheme, shrToken, pcfg.Oauth.RedirectHost, pcfg.Oauth.RedirectPort, provider, url.QueryEscape(target), authCheckInterval.String()), http.StatusFound)
func oauthLoginRequired(w http.ResponseWriter, r *http.Request, cfg *OauthConfig, provider, target string, authCheckInterval time.Duration) {
http.Redirect(w, r, fmt.Sprintf("%s/%s/login?targethost=%s&checkInterval=%s", cfg.RedirectUrl, provider, url.QueryEscape(target), authCheckInterval.String()), http.StatusFound)
}
func resolveService(hostMatch string, host string) string {

View File

@ -2,10 +2,6 @@ package endpoints
import "time"
type RequestHandler interface {
Requests() func() int32
}
type Request struct {
Stamp time.Time
RemoteAddr string

21
etc/caddy/README.md Normal file
View File

@ -0,0 +1,21 @@
# Caddyfile Samples
The Caddyfile samples in this directory are for use with `--backend-mode caddy ./my.Caddyfile` which runs an embedded
Caddy server.
With a zrok reserved share, you have the option to permanently override the path to the Caddyfile when you run `zrok
share reserved ${ZROK_RESERVED_TOKEN} --override-endpoint new.Caddyfile`.
The Caddyfile must have this structure because it is rendered as a Go template by zrok to bind the HTTP listener.
```console
http:// {
bind {{ .ZrokBindAddress }}
# customize reverse_proxy, file_server, etc.
}
```
## Notes
multiple_upstream.Caddyfile is bundled in the zrok-share package for Linux as an example Caddyfile.

View File

@ -2,18 +2,24 @@
#
http:// {
# Bind to the zrok share
bind {{ .ZrokBindAddress }}
bind {{ .ZrokBindAddress }}
# Handle paths starting with `/zrok/*`
# This will also strip the `/zrok/` from the path before sending to the backend
handle_path /zrok/* {
reverse_proxy https://zrok.io {
header_up Host zrok.io
}
}
handle_path /zrok/* {
reverse_proxy https://zrok.io {
header_up Host zrok.io
}
}
# All other traffic goes to localhost:3000
reverse_proxy /* 127.0.0.1:3000 {
header_up Host localhost:3000
}
# serve index.html if it exists, else a file index
handle_path /zrok-static/* {
root * /var/www/html
file_server browse
}
# All other traffic goes to localhost:3000
reverse_proxy /* 127.0.0.1:3000 {
header_up Host localhost:3000
}
}

View File

@ -2,7 +2,7 @@
# configuration, the software will expect this field to be incremented. This protects you against invalid configuration
# versions and will refer to you to the documentation when the configuration structure changes.
#
v: 2
v: 3
# Setting the `host_match` setting will cause a `zrok access public` to ignore `Host` headers that do not contain the
# configured string. This will allow you to let a load balancer access the frontend by IP address for health check
@ -13,16 +13,19 @@ v: 2
# The OAuth configuration is used when enabling OAuth authentication with your public frontend.
#
#oauth:
# # `redirect_host` and `redirect_port` should correspond with the DNS hostname and URL representing
# # the OAuth frontend you'll use with your installation.
# # `bind_address` is the <address:port> of the interface where the OAuth frontend listener should
# # bind
# #
# redirect_host: oauth.zrok.io
# redirect_port: 28080
# bind_address: 127.0.0.1:8181
#
# # `redirect_http_only` will generate an HTTP URI for your OAuth frontend, rather than HTTPS. This
# # should only be set to `true` in development environments.
# # `redirect_url` is the <scheme://address[:port]> of the URL where OAuth requests should be directed.
# #
# redirect_http_only: false
# redirect_url: https://oauth.zrok.io
#
# # `cookie_domain` is the domain where the authentication cookies should be applied. Should likely match
# # the `host_match` specified above.
# #
# cookie_domain: zrok.io
#
# # `hash_key` is a unique key for your installation that is used to secure authentication payloads
# # with OAuth providers.

4
nfpm/README.md Normal file
View File

@ -0,0 +1,4 @@
# nfpm supporting files
These files are sourced by nfpm when invoked by goreleaser to build Linux packages.

58
nfpm/zrok-enable.bash Normal file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env bash
#
# this script uses a zrok enable token to enable a zrok environment in $HOME/.zrok
#
set -o errexit
set -o nounset
set -o pipefail
BASENAME=$(basename "$0")
DEFAULT_ZROK_ENVIRONMENT_NAME="zrok-share.service on $(hostname -s)"
if (( $# )); then
case $1 in
-h|*help)
echo -e \
"Usage: ${BASENAME} FILENAME\n"\
"\tFILENAME\tfile containing environment variables to set"
exit 0
;;
esac
fi
# set HOME to the first colon-sep dir in STATE_DIRECTORY inherited from systemd, e.g. /var/lib/zrok-share
if [[ -n "${STATE_DIRECTORY:-}" ]]; then
export HOME="${STATE_DIRECTORY%:*}"
else
echo "ERROR: STATE_DIRECTORY is undefined. This script must be run from systemd because it runs as a"\
"dynamically-allocated user and exclusively manages the files in STATE_DIRECTORY" >&2
exit 1
fi
if [[ -s ~/.zrok/environment.json ]]; then
echo "INFO: zrok environment is already enabled. Delete '$(realpath ~/.zrok/environment.json)' if you want to create a"\
"new environment."
exit 0
fi
if (( $# )); then
if [[ -s "$1" ]]; then
source "$1"
else
echo "ERROR: \$1="$1" is empty or not a readable file" >&2
exit 1
fi
else
echo "ERROR: need filename argument to read environment configuration" >&2
exit 1
fi
if [[ -z "${ZROK_ENABLE_TOKEN}" ]]; then
echo "ERROR: ZROK_ENABLE_TOKEN is not defined" >&2
exit 1
else
zrok config set apiEndpoint "${ZROK_API_ENDPOINT:-https://api.zrok.io}"
echo "INFO: running: zrok enable ..."
exec zrok enable --headless --description "${ZROK_ENVIRONMENT_NAME:-${DEFAULT_ZROK_ENVIRONMENT_NAME}}" "${ZROK_ENABLE_TOKEN}"
fi

133
nfpm/zrok-share.bash Normal file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env bash
#
# this script shares the configured backend for a reserved share token
#
set -o errexit
set -o nounset
set -o pipefail
if ! command -v jq &>/dev/null; then
echo "ERROR: jq is needed but not installed" >&2
exit 1
fi
# set HOME to the first colon-sep dir in STATE_DIRECTORY inherited from systemd, e.g. /var/lib/zrok-share
export HOME="${STATE_DIRECTORY%:*}"
if (( $# )); then
if [[ -s "$1" ]]; then
source "$1"
else
echo "ERROR: '$1' is empty or not readable" >&2
exit 1
fi
else
# TODO: consider defining a default environment file
# if [[ -s /opt/openziti/etc/zrok.env ]]; then
# source /opt/openziti/etc/zrok.env
# else
# echo "ERROR: need /opt/openziti/etc/zrok.env or filename argument to read share configuration" >&2
# exit 1
# fi
echo "ERROR: need filename argument to read share configuration" >&2
exit 1
fi
if [[ -s ~/.zrok/reserved.json ]]; then
ZROK_RESERVED_TOKEN="$(jq '.token' ~/.zrok/reserved.json 2>/dev/null)"
if [[ -z "${ZROK_RESERVED_TOKEN}" || "${ZROK_RESERVED_TOKEN}" == null ]]; then
echo "ERROR: invalid reserved.json: '$(jq -c . ~/.zrok/reserved.json)'" >&2
exit 1
else
echo "INFO: zrok backend is already reserved: ${ZROK_RESERVED_TOKEN}"
fi
else
ZROK_CMD="reserve public --json-output ${ZROK_VERBOSE:-}"
[[ -n "${ZROK_TARGET:-}" ]] || {
echo "ERROR: ZROK_TARGET was not defined in /opt/openziti/etc/zrok/zrok-share.env." >&2
exit 1
}
[[ -n "${ZROK_BACKEND_MODE:-}" ]] || {
echo "WARNING: ZROK_BACKEND_MODE was not defined, assuming mode 'proxy'." >&2
ZROK_BACKEND_MODE="proxy"
}
case "${ZROK_BACKEND_MODE}" in
proxy)
if ! [[ "${ZROK_TARGET}" =~ ^https?:// ]]; then
echo "ERROR: ZROK_TARGET='${ZROK_TARGET}' is not an HTTP URL" >&2
exit 1
else
echo "INFO: validated backend mode ${ZROK_BACKEND_MODE} and target ${ZROK_TARGET}"
fi
;;
caddy)
if ! [[ "${ZROK_TARGET}" =~ ^/ ]]; then
echo "ERROR: ZROK_TARGET='${ZROK_TARGET}' is not an absolute filesystem path." >&2
exit 1
elif ! [[ -f "${ZROK_TARGET}" && -r "${ZROK_TARGET}" ]]; then
echo "ERROR: ZROK_TARGET='${ZROK_TARGET}' is not a readable regular file" >&2
exit 1
else
echo "INFO: validated backend mode ${ZROK_BACKEND_MODE} and target ${ZROK_TARGET}"
fi
;;
web|drive)
if ! [[ "${ZROK_TARGET}" =~ ^/ ]]; then
echo "ERROR: ZROK_TARGET='${ZROK_TARGET}' is not an absolute filesystem path." >&2
exit 1
elif ! [[ -d "${ZROK_TARGET}" && -r "${ZROK_TARGET}" ]]; then
echo "ERROR: ZROK_TARGET='${ZROK_TARGET}' is not a readable directory" >&2
exit 1
else
echo "INFO: validated backend mode ${ZROK_BACKEND_MODE} and target ${ZROK_TARGET}"
fi
;;
*)
echo "WARNING: ZROK_BACKEND_MODE='${ZROK_BACKEND_MODE}' is not a recognized mode for a zrok public share."\
" ZROK_TARGET value will not validated before running." >&2
;;
esac
ZROK_CMD+=" --backend-mode ${ZROK_BACKEND_MODE} ${ZROK_TARGET}"
if [[ -n "${ZROK_SHARE_OPTS:-}" ]]; then
ZROK_CMD+=" ${ZROK_SHARE_OPTS}"
fi
if [[ -n "${ZROK_OAUTH_PROVIDER:-}" ]]; then
ZROK_CMD+=" --oauth-provider ${ZROK_OAUTH_PROVIDER}"
fi
if [[ -n "${ZROK_OAUTH_EMAILS:-}" ]]; then
for EMAIL in ${ZROK_OAUTH_EMAILS}; do
if ! [[ ${EMAIL} =~ @ ]]; then
echo "WARNING: '${EMAIL}' does not contain '@' so it may match more than one email domain!" >&2
fi
ZROK_CMD+=" --oauth-email-domains ${EMAIL}"
done
fi
echo "INFO: running: zrok ${ZROK_CMD}"
zrok ${ZROK_CMD} | jq -rc | tee ~/.zrok/reserved.json
fi
if ! [[ -s ~/.zrok/reserved.json ]]; then
echo "ERROR: empty or missing $(realpath ~/.zrok)/reserved.json" >&2
exit 1
else
ZROK_PUBLIC_URLS=$(jq -cr '.frontend_endpoints' ~/.zrok/reserved.json 2>/dev/null)
if [[ -z "${ZROK_PUBLIC_URLS}" || "${ZROK_PUBLIC_URLS}" == null ]]; then
echo "ERROR: frontend endpoints not defined in $(realpath ~/.zrok)/reserved.json" >&2
exit 1
else
echo "INFO: zrok public URLs: ${ZROK_PUBLIC_URLS}"
fi
ZROK_RESERVED_TOKEN=$(jq -r '.token' ~/.zrok/reserved.json 2>/dev/null)
if [[ -z "${ZROK_RESERVED_TOKEN}" || "${ZROK_RESERVED_TOKEN}" == null ]]; then
echo "ERROR: zrok reservation token not defined in $(realpath ~/.zrok)/reserved.json" >&2
exit 1
fi
ZROK_CMD="share reserved ${ZROK_RESERVED_TOKEN} --headless --override-endpoint ${ZROK_TARGET}"
ZROK_CMD+=" ${ZROK_VERBOSE:-} ${ZROK_INSECURE:-}"
if [[ -n "${ZROK_SHARE_OPTS:-}" ]]; then
ZROK_CMD+=" ${ZROK_SHARE_OPTS}"
fi
echo "INFO: running: zrok ${ZROK_CMD}"
exec zrok ${ZROK_CMD}
fi

78
nfpm/zrok-share.env Normal file
View File

@ -0,0 +1,78 @@
# These values are sourced by the zrok-share.service. Search for "MUST" to identify the values that need to be changed.
#
## ZROK ENVIRONMENT
#
# You MUST enable a zrok environment by setting the environment enable token here. This file must be readable by
# 'other'. Obtain the enable token from the zrok console after accepting your invitation and creating a password.
#
# WARNING: changing these values has no effect if /var/lib/zrok-share/.zrok/environment.json exists. Remove that file to
# enable a new environment and /var/lib/zrok-share/.zrok/reserved.json to provision a new frontend URL for the specified
# target.
#
ZROK_ENABLE_TOKEN=""
#
# You MAY customize the environment name that appears in the zrok console.
#
ZROK_ENVIRONMENT_NAME=""
# You MUST set this only if self-hosting the zrok controller.
#ZROK_API_ENDPOINT="https://api.zrok.io"
#
## ZROK BACKEND TARGET
#
# You MUST define the backend target and mode. The frontend URL will be provisioned when the service starts. You MAY
# change ZROK_TARGET and frontend URL will remain the same after a restart as long as the backend mode and frontend
# authentication options are the same. Options that require provisioning a new frontend URL when changed are marked with
# WARNING. You may delete /var/lib/zrok-share/.zrok/reserved.json and restart the service to provision a new frontend URL.
#
# backend-mode "proxy" (default): share a backend web server URL that's reachable by this host; must begin with 'http://' or
# 'https://'; must accept the HOST header of the proxy frontend. Check out backend mode "caddy" if you need more control.
ZROK_TARGET="" # e.g., http://127.0.0.1:3000
ZROK_BACKEND_MODE="proxy"
# if defined, an https share's backend server certificate will not be verified with backend-mode 'proxy'
# NOTE: changing this value does not require provisioning a new frontend URL
#ZROK_INSECURE="--insecure"
# backend-mode "web": run a web server and share a static HTML directory that's present on this host. Must be an
# absolute path to a directory that is readable by 'other'
#ZROK_TARGET="/var/www/html"
#ZROK_BACKEND_MODE="web"
# backend-mode "drive": run a WebDAV file server sharing a directory that's present on this host. Must be an absolute
# path to a directory that is readable by 'other'
#ZROK_TARGET="/usr/share/doc"
#ZROK_BACKEND_MODE="drive"
# backend-mode "caddy": run an embedded Caddy server configured by the supplied Caddyfile. Must be an absolute path that
# is readable by 'other'.
#ZROK_TARGET="/opt/openziti/etc/zrok/multiple_upstream.Caddyfile"
#ZROK_BACKEND_MODE="caddy"
# DEBUG log level
# NOTE: changing this value does not require provisioning a new frontend URL
#ZROK_VERBOSE="--verbose"
# you MAY set additional command-line options for the share; see "zrok reserve public --help" for hints
# WARNING: changing this value requires provisioning a new frontend URL
# NOTE: basic auth and oauth are mutually exclusive
ZROK_SHARE_OPTS=""
#
## ZROK FRONTEND
#
# you MAY set one OAuth2/OIDC provider; "google" and "github" are valid for the default instance api.zrok.io
# WARNING: changing this value requires provisioning a new frontend URL
# NOTE: basic auth and oauth are mutually exclusive
#ZROK_OAUTH_PROVIDER="google"
# you MAY restrict access to one or more email addresses or domains; must be a space-separate list
# WARNING: changing this value requires provisioning a new frontend URL
#ZROK_OAUTH_EMAILS="bob@acme.example.com alice@forge.example.com @corp.example.com"
# set if self-hosting zrok and not using only the default frontend name 'public'; must be a space-separated list
# WARNING: changing this value requires provisioning a new frontend URL
#ZROK_FRONTENDS="public"

17
nfpm/zrok-share.service Normal file
View File

@ -0,0 +1,17 @@
[Unit]
Description=zrok reserved public share service
After=network-online.target
[Service]
Type=simple
DynamicUser=yes
StateDirectory=zrok-share
UMask=0007
Environment=PFXLOG_NO_JSON=true
ExecStartPre=/opt/openziti/bin/zrok-enable.bash /opt/openziti/etc/zrok/zrok-share.env
ExecStart=/opt/openziti/bin/zrok-share.bash /opt/openziti/etc/zrok/zrok-share.env
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target

View File

@ -28,7 +28,7 @@ type ShareRequest struct {
AuthUsers []*AuthUser `json:"authUsers"`
// backend mode
// Enum: [proxy web tcpTunnel udpTunnel caddy]
// Enum: [proxy web tcpTunnel udpTunnel caddy drive]
BackendMode string `json:"backendMode,omitempty"`
// backend proxy endpoint
@ -114,7 +114,7 @@ var shareRequestTypeBackendModePropEnum []interface{}
func init() {
var res []string
if err := json.Unmarshal([]byte(`["proxy","web","tcpTunnel","udpTunnel","caddy"]`), &res); err != nil {
if err := json.Unmarshal([]byte(`["proxy","web","tcpTunnel","udpTunnel","caddy","drive"]`), &res); err != nil {
panic(err)
}
for _, v := range res {
@ -138,6 +138,9 @@ const (
// ShareRequestBackendModeCaddy captures enum value "caddy"
ShareRequestBackendModeCaddy string = "caddy"
// ShareRequestBackendModeDrive captures enum value "drive"
ShareRequestBackendModeDrive string = "drive"
)
// prop value enum

View File

@ -1472,7 +1472,8 @@ func init() {
"web",
"tcpTunnel",
"udpTunnel",
"caddy"
"caddy",
"drive"
]
},
"backendProxyEndpoint": {
@ -3088,7 +3089,8 @@ func init() {
"web",
"tcpTunnel",
"udpTunnel",
"caddy"
"caddy",
"drive"
]
},
"backendProxyEndpoint": {

View File

@ -10,6 +10,7 @@ const (
TcpTunnelBackendMode BackendMode = "tcpTunnel"
UdpTunnelBackendMode BackendMode = "udpTunnel"
CaddyBackendMode BackendMode = "caddy"
DriveBackendMode BackendMode = "drive"
)
type ShareMode string
@ -20,6 +21,7 @@ const (
)
type ShareRequest struct {
Reserved bool
BackendMode BackendMode
ShareMode ShareMode
Target string
@ -31,8 +33,8 @@ type ShareRequest struct {
}
type Share struct {
Token string
FrontendEndpoints []string
Token string `json:"token"`
FrontendEndpoints []string `json:"frontend_endpoints"`
}
type AccessRequest struct {

View File

@ -25,6 +25,7 @@ func CreateShare(root env_core.Root, request *ShareRequest) (*Share, error) {
default:
return nil, errors.Errorf("unknown share mode '%v'", request.ShareMode)
}
out.Body.Reserved = request.Reserved
if len(request.BasicAuth) > 0 {
out.Body.AuthScheme = string(Basic)

View File

@ -971,7 +971,7 @@ definitions:
type: string
backendMode:
type: string
enum: ["proxy", "web", "tcpTunnel", "udpTunnel", "caddy"]
enum: ["proxy", "web", "tcpTunnel", "udpTunnel", "caddy", "drive"]
backendProxyEndpoint:
type: string
authScheme:

View File

@ -14,9 +14,9 @@
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
"@docusaurus/core": "^2.4.1",
"@docusaurus/plugin-client-redirects": "^2.4.1",
"@docusaurus/preset-classic": "^2.4.1",
"@docusaurus/core": "^2.4.3",
"@docusaurus/plugin-client-redirects": "^2.4.3",
"@docusaurus/preset-classic": "^2.4.3",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5",
@ -25,7 +25,7 @@
"remark-math": "^5.1.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^2.4.1"
"@docusaurus/module-type-aliases": "^2.4.3"
},
"browserslist": {
"production": [

View File

@ -177,4 +177,9 @@ a code {
.navbar__link {
color: var(--ifm-navbar-link-color);
font-weight: var(--ifm-font-weight-semibold);
}
}
/* hide the clipboard copy button on code blocks of type "buttonless" */
.language-buttonless div > button {
display: none;
}

View File

@ -1254,10 +1254,10 @@
"@docsearch/css" "3.5.1"
algoliasearch "^4.0.0"
"@docusaurus/core@2.4.1", "@docusaurus/core@^2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.4.1.tgz#4b8ff5766131ce3fbccaad0b1daf2ad4dc76f62d"
integrity sha512-SNsY7PshK3Ri7vtsLXVeAJGS50nJN3RgF836zkyUfAD01Fq+sAk5EwWgLw+nnm5KVNGDu7PRR2kRGDsWvqpo0g==
"@docusaurus/core@2.4.3", "@docusaurus/core@^2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.4.3.tgz#d86624901386fd8164ce4bff9cc7f16fde57f523"
integrity sha512-dWH5P7cgeNSIg9ufReX6gaCl/TmrGKD38Orbwuz05WPhAQtFXHd5B8Qym1TiXfvUNvwoYKkAJOJuGe8ou0Z7PA==
dependencies:
"@babel/core" "^7.18.6"
"@babel/generator" "^7.18.7"
@ -1269,13 +1269,13 @@
"@babel/runtime" "^7.18.6"
"@babel/runtime-corejs3" "^7.18.6"
"@babel/traverse" "^7.18.8"
"@docusaurus/cssnano-preset" "2.4.1"
"@docusaurus/logger" "2.4.1"
"@docusaurus/mdx-loader" "2.4.1"
"@docusaurus/cssnano-preset" "2.4.3"
"@docusaurus/logger" "2.4.3"
"@docusaurus/mdx-loader" "2.4.3"
"@docusaurus/react-loadable" "5.5.2"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-common" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-common" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
"@slorber/static-site-generator-webpack-plugin" "^4.0.7"
"@svgr/webpack" "^6.2.1"
autoprefixer "^10.4.7"
@ -1331,33 +1331,33 @@
webpack-merge "^5.8.0"
webpackbar "^5.0.2"
"@docusaurus/cssnano-preset@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.1.tgz#eacadefb1e2e0f59df3467a0fe83e4ff79eed163"
integrity sha512-ka+vqXwtcW1NbXxWsh6yA1Ckii1klY9E53cJ4O9J09nkMBgrNX3iEFED1fWdv8wf4mJjvGi5RLZ2p9hJNjsLyQ==
"@docusaurus/cssnano-preset@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.3.tgz#1d7e833c41ce240fcc2812a2ac27f7b862f32de0"
integrity sha512-ZvGSRCi7z9wLnZrXNPG6DmVPHdKGd8dIn9pYbEOFiYihfv4uDR3UtxogmKf+rT8ZlKFf5Lqne8E8nt08zNM8CA==
dependencies:
cssnano-preset-advanced "^5.3.8"
postcss "^8.4.14"
postcss-sort-media-queries "^4.2.1"
tslib "^2.4.0"
"@docusaurus/logger@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.4.1.tgz#4d2c0626b40752641f9fdd93ad9b5a7a0792f767"
integrity sha512-5h5ysIIWYIDHyTVd8BjheZmQZmEgWDR54aQ1BX9pjFfpyzFo5puKXKYrYJXbjEHGyVhEzmB9UXwbxGfaZhOjcg==
"@docusaurus/logger@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-2.4.3.tgz#518bbc965fb4ebe8f1d0b14e5f4161607552d34c"
integrity sha512-Zxws7r3yLufk9xM1zq9ged0YHs65mlRmtsobnFkdZTxWXdTYlWWLWdKyNKAsVC+D7zg+pv2fGbyabdOnyZOM3w==
dependencies:
chalk "^4.1.2"
tslib "^2.4.0"
"@docusaurus/mdx-loader@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.4.1.tgz#6425075d7fc136dbfdc121349060cedd64118393"
integrity sha512-4KhUhEavteIAmbBj7LVFnrVYDiU51H5YWW1zY6SmBSte/YLhDutztLTBE0PQl1Grux1jzUJeaSvAzHpTn6JJDQ==
"@docusaurus/mdx-loader@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-2.4.3.tgz#e8ff37f30a060eaa97b8121c135f74cb531a4a3e"
integrity sha512-b1+fDnWtl3GiqkL0BRjYtc94FZrcDDBV1j8446+4tptB9BAOlePwG2p/pK6vGvfL53lkOsszXMghr2g67M0vCw==
dependencies:
"@babel/parser" "^7.18.8"
"@babel/traverse" "^7.18.8"
"@docusaurus/logger" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/logger" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@mdx-js/mdx" "^1.6.22"
escape-html "^1.0.3"
file-loader "^6.2.0"
@ -1372,13 +1372,13 @@
url-loader "^4.1.1"
webpack "^5.73.0"
"@docusaurus/module-type-aliases@2.4.1", "@docusaurus/module-type-aliases@^2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.1.tgz#38b3c2d2ae44bea6d57506eccd84280216f0171c"
integrity sha512-gLBuIFM8Dp2XOCWffUDSjtxY7jQgKvYujt7Mx5s4FCTfoL5dN1EVbnrn+O2Wvh8b0a77D57qoIDY7ghgmatR1A==
"@docusaurus/module-type-aliases@2.4.3", "@docusaurus/module-type-aliases@^2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.3.tgz#d08ef67e4151e02f352a2836bcf9ecde3b9c56ac"
integrity sha512-cwkBkt1UCiduuvEAo7XZY01dJfRn7UR/75mBgOdb1hKknhrabJZ8YH+7savd/y9kLExPyrhe0QwdS9GuzsRRIA==
dependencies:
"@docusaurus/react-loadable" "5.5.2"
"@docusaurus/types" "2.4.1"
"@docusaurus/types" "2.4.3"
"@types/history" "^4.7.11"
"@types/react" "*"
"@types/react-router-config" "*"
@ -1386,33 +1386,33 @@
react-helmet-async "*"
react-loadable "npm:@docusaurus/react-loadable@5.5.2"
"@docusaurus/plugin-client-redirects@^2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-2.4.1.tgz#a28afcc4a1cb7657168ce37a57efd3194c20a53a"
integrity sha512-tp0j16gaLIJ4p+IR0P6KDOFsTOGGMY54MNPnmM61Vaqqt5omLqsuKUO8UlCGU1oW/4EIQOhXYy99XYY5MjE+7A==
"@docusaurus/plugin-client-redirects@^2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-client-redirects/-/plugin-client-redirects-2.4.3.tgz#0da7e6facadbca3bd7cb8d0453f21bea7f4f1721"
integrity sha512-iCwc/zH8X6eNtLYdyUJFY6+GbsbRgMgvAC/TmSmCYTmwnoN5Y1Bc5OwUkdtoch0XKizotJMRAmGIAhP8sAetdQ==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/logger" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-common" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/logger" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-common" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
eta "^2.0.0"
fs-extra "^10.1.0"
lodash "^4.17.21"
tslib "^2.4.0"
"@docusaurus/plugin-content-blog@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.1.tgz#c705a8b1a36a34f181dcf43b7770532e4dcdc4a3"
integrity sha512-E2i7Knz5YIbE1XELI6RlTnZnGgS52cUO4BlCiCUCvQHbR+s1xeIWz4C6BtaVnlug0Ccz7nFSksfwDpVlkujg5Q==
"@docusaurus/plugin-content-blog@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.3.tgz#6473b974acab98e967414d8bbb0d37e0cedcea14"
integrity sha512-PVhypqaA0t98zVDpOeTqWUTvRqCEjJubtfFUQ7zJNYdbYTbS/E/ytq6zbLVsN/dImvemtO/5JQgjLxsh8XLo8Q==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/logger" "2.4.1"
"@docusaurus/mdx-loader" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-common" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/logger" "2.4.3"
"@docusaurus/mdx-loader" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-common" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
cheerio "^1.0.0-rc.12"
feed "^4.2.2"
fs-extra "^10.1.0"
@ -1423,18 +1423,18 @@
utility-types "^3.10.0"
webpack "^5.73.0"
"@docusaurus/plugin-content-docs@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.1.tgz#ed94d9721b5ce7a956fb01cc06c40d8eee8dfca7"
integrity sha512-Lo7lSIcpswa2Kv4HEeUcGYqaasMUQNpjTXpV0N8G6jXgZaQurqp7E8NGYeGbDXnb48czmHWbzDL4S3+BbK0VzA==
"@docusaurus/plugin-content-docs@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.3.tgz#aa224c0512351e81807adf778ca59fd9cd136973"
integrity sha512-N7Po2LSH6UejQhzTCsvuX5NOzlC+HiXOVvofnEPj0WhMu1etpLEXE6a4aTxrtg95lQ5kf0xUIdjX9sh3d3G76A==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/logger" "2.4.1"
"@docusaurus/mdx-loader" "2.4.1"
"@docusaurus/module-type-aliases" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/logger" "2.4.3"
"@docusaurus/mdx-loader" "2.4.3"
"@docusaurus/module-type-aliases" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
"@types/react-router-config" "^5.0.6"
combine-promises "^1.1.0"
fs-extra "^10.1.0"
@ -1445,95 +1445,95 @@
utility-types "^3.10.0"
webpack "^5.73.0"
"@docusaurus/plugin-content-pages@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.1.tgz#c534f7e49967699a45bbe67050d1605ebbf3d285"
integrity sha512-/UjuH/76KLaUlL+o1OvyORynv6FURzjurSjvn2lbWTFc4tpYY2qLYTlKpTCBVPhlLUQsfyFnshEJDLmPneq2oA==
"@docusaurus/plugin-content-pages@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.3.tgz#7f285e718b53da8c8d0101e70840c75b9c0a1ac0"
integrity sha512-txtDVz7y3zGk67q0HjG0gRttVPodkHqE0bpJ+7dOaTH40CQFLSh7+aBeGnPOTl+oCPG+hxkim4SndqPqXjQ8Bg==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/mdx-loader" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/mdx-loader" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
fs-extra "^10.1.0"
tslib "^2.4.0"
webpack "^5.73.0"
"@docusaurus/plugin-debug@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.4.1.tgz#461a2c77b0c5a91b2c05257c8f9585412aaa59dc"
integrity sha512-7Yu9UPzRShlrH/G8btOpR0e6INFZr0EegWplMjOqelIwAcx3PKyR8mgPTxGTxcqiYj6hxSCRN0D8R7YrzImwNA==
"@docusaurus/plugin-debug@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-2.4.3.tgz#2f90eb0c9286a9f225444e3a88315676fe02c245"
integrity sha512-LkUbuq3zCmINlFb+gAd4ZvYr+bPAzMC0hwND4F7V9bZ852dCX8YoWyovVUBKq4er1XsOwSQaHmNGtObtn8Av8Q==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils" "2.4.3"
fs-extra "^10.1.0"
react-json-view "^1.21.3"
tslib "^2.4.0"
"@docusaurus/plugin-google-analytics@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.1.tgz#30de1c35773bf9d52bb2d79b201b23eb98022613"
integrity sha512-dyZJdJiCoL+rcfnm0RPkLt/o732HvLiEwmtoNzOoz9MSZz117UH2J6U2vUDtzUzwtFLIf32KkeyzisbwUCgcaQ==
"@docusaurus/plugin-google-analytics@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.3.tgz#0d19993136ade6f7a7741251b4f617400d92ab45"
integrity sha512-KzBV3k8lDkWOhg/oYGxlK5o9bOwX7KpPc/FTWoB+SfKhlHfhq7qcQdMi1elAaVEIop8tgK6gD1E58Q+XC6otSQ==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
tslib "^2.4.0"
"@docusaurus/plugin-google-gtag@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.1.tgz#6a3eb91022714735e625c7ca70ef5188fa7bd0dc"
integrity sha512-mKIefK+2kGTQBYvloNEKtDmnRD7bxHLsBcxgnbt4oZwzi2nxCGjPX6+9SQO2KCN5HZbNrYmGo5GJfMgoRvy6uA==
"@docusaurus/plugin-google-gtag@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.3.tgz#e1a80b0696771b488562e5b60eff21c9932d9e1c"
integrity sha512-5FMg0rT7sDy4i9AGsvJC71MQrqQZwgLNdDetLEGDHLfSHLvJhQbTCUGbGXknUgWXQJckcV/AILYeJy+HhxeIFA==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
tslib "^2.4.0"
"@docusaurus/plugin-google-tag-manager@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.1.tgz#b99f71aec00b112bbf509ef2416e404a95eb607e"
integrity sha512-Zg4Ii9CMOLfpeV2nG74lVTWNtisFaH9QNtEw48R5QE1KIwDBdTVaiSA18G1EujZjrzJJzXN79VhINSbOJO/r3g==
"@docusaurus/plugin-google-tag-manager@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.3.tgz#e41fbf79b0ffc2de1cc4013eb77798cff0ad98e3"
integrity sha512-1jTzp71yDGuQiX9Bi0pVp3alArV0LSnHXempvQTxwCGAEzUWWaBg4d8pocAlTpbP9aULQQqhgzrs8hgTRPOM0A==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
tslib "^2.4.0"
"@docusaurus/plugin-sitemap@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.1.tgz#8a7a76ed69dc3e6b4474b6abb10bb03336a9de6d"
integrity sha512-lZx+ijt/+atQ3FVE8FOHV/+X3kuok688OydDXrqKRJyXBJZKgGjA2Qa8RjQ4f27V2woaXhtnyrdPop/+OjVMRg==
"@docusaurus/plugin-sitemap@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.3.tgz#1b3930900a8f89670ce7e8f83fb4730cd3298c32"
integrity sha512-LRQYrK1oH1rNfr4YvWBmRzTL0LN9UAPxBbghgeFRBm5yloF6P+zv1tm2pe2hQTX/QP5bSKdnajCvfnScgKXMZQ==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/logger" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-common" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/logger" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-common" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
fs-extra "^10.1.0"
sitemap "^7.1.1"
tslib "^2.4.0"
"@docusaurus/preset-classic@^2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.4.1.tgz#072f22d0332588e9c5f512d4bded8d7c99f91497"
integrity sha512-P4//+I4zDqQJ+UDgoFrjIFaQ1MeS9UD1cvxVQaI6O7iBmiHQm0MGROP1TbE7HlxlDPXFJjZUK3x3cAoK63smGQ==
"@docusaurus/preset-classic@^2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-2.4.3.tgz#074c57ebf29fa43d23bd1c8ce691226f542bc262"
integrity sha512-tRyMliepY11Ym6hB1rAFSNGwQDpmszvWYJvlK1E+md4SW8i6ylNHtpZjaYFff9Mdk3i/Pg8ItQq9P0daOJAvQw==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/plugin-content-blog" "2.4.1"
"@docusaurus/plugin-content-docs" "2.4.1"
"@docusaurus/plugin-content-pages" "2.4.1"
"@docusaurus/plugin-debug" "2.4.1"
"@docusaurus/plugin-google-analytics" "2.4.1"
"@docusaurus/plugin-google-gtag" "2.4.1"
"@docusaurus/plugin-google-tag-manager" "2.4.1"
"@docusaurus/plugin-sitemap" "2.4.1"
"@docusaurus/theme-classic" "2.4.1"
"@docusaurus/theme-common" "2.4.1"
"@docusaurus/theme-search-algolia" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/plugin-content-blog" "2.4.3"
"@docusaurus/plugin-content-docs" "2.4.3"
"@docusaurus/plugin-content-pages" "2.4.3"
"@docusaurus/plugin-debug" "2.4.3"
"@docusaurus/plugin-google-analytics" "2.4.3"
"@docusaurus/plugin-google-gtag" "2.4.3"
"@docusaurus/plugin-google-tag-manager" "2.4.3"
"@docusaurus/plugin-sitemap" "2.4.3"
"@docusaurus/theme-classic" "2.4.3"
"@docusaurus/theme-common" "2.4.3"
"@docusaurus/theme-search-algolia" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2":
version "5.5.2"
@ -1543,23 +1543,23 @@
"@types/react" "*"
prop-types "^15.6.2"
"@docusaurus/theme-classic@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.4.1.tgz#0060cb263c1a73a33ac33f79bb6bc2a12a56ad9e"
integrity sha512-Rz0wKUa+LTW1PLXmwnf8mn85EBzaGSt6qamqtmnh9Hflkc+EqiYMhtUJeLdV+wsgYq4aG0ANc+bpUDpsUhdnwg==
"@docusaurus/theme-classic@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-2.4.3.tgz#29360f2eb03a0e1686eb19668633ef313970ee8f"
integrity sha512-QKRAJPSGPfDY2yCiPMIVyr+MqwZCIV2lxNzqbyUW0YkrlmdzzP3WuQJPMGLCjWgQp/5c9kpWMvMxjhpZx1R32Q==
dependencies:
"@docusaurus/core" "2.4.1"
"@docusaurus/mdx-loader" "2.4.1"
"@docusaurus/module-type-aliases" "2.4.1"
"@docusaurus/plugin-content-blog" "2.4.1"
"@docusaurus/plugin-content-docs" "2.4.1"
"@docusaurus/plugin-content-pages" "2.4.1"
"@docusaurus/theme-common" "2.4.1"
"@docusaurus/theme-translations" "2.4.1"
"@docusaurus/types" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-common" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/mdx-loader" "2.4.3"
"@docusaurus/module-type-aliases" "2.4.3"
"@docusaurus/plugin-content-blog" "2.4.3"
"@docusaurus/plugin-content-docs" "2.4.3"
"@docusaurus/plugin-content-pages" "2.4.3"
"@docusaurus/theme-common" "2.4.3"
"@docusaurus/theme-translations" "2.4.3"
"@docusaurus/types" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-common" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
"@mdx-js/react" "^1.6.22"
clsx "^1.2.1"
copy-text-to-clipboard "^3.0.1"
@ -1574,18 +1574,18 @@
tslib "^2.4.0"
utility-types "^3.10.0"
"@docusaurus/theme-common@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.4.1.tgz#03e16f7aa96455e952f3243ac99757b01a3c83d4"
integrity sha512-G7Zau1W5rQTaFFB3x3soQoZpkgMbl/SYNG8PfMFIjKa3M3q8n0m/GRf5/H/e5BqOvt8c+ZWIXGCiz+kUCSHovA==
"@docusaurus/theme-common@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-2.4.3.tgz#bb31d70b6b67d0bdef9baa343192dcec49946a2e"
integrity sha512-7KaDJBXKBVGXw5WOVt84FtN8czGWhM0lbyWEZXGp8AFfL6sZQfRTluFp4QriR97qwzSyOfQb+nzcDZZU4tezUw==
dependencies:
"@docusaurus/mdx-loader" "2.4.1"
"@docusaurus/module-type-aliases" "2.4.1"
"@docusaurus/plugin-content-blog" "2.4.1"
"@docusaurus/plugin-content-docs" "2.4.1"
"@docusaurus/plugin-content-pages" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-common" "2.4.1"
"@docusaurus/mdx-loader" "2.4.3"
"@docusaurus/module-type-aliases" "2.4.3"
"@docusaurus/plugin-content-blog" "2.4.3"
"@docusaurus/plugin-content-docs" "2.4.3"
"@docusaurus/plugin-content-pages" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-common" "2.4.3"
"@types/history" "^4.7.11"
"@types/react" "*"
"@types/react-router-config" "*"
@ -1596,19 +1596,19 @@
use-sync-external-store "^1.2.0"
utility-types "^3.10.0"
"@docusaurus/theme-search-algolia@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.1.tgz#906bd2cca3fced0241985ef502c892f58ff380fc"
integrity sha512-6BcqW2lnLhZCXuMAvPRezFs1DpmEKzXFKlYjruuas+Xy3AQeFzDJKTJFIm49N77WFCTyxff8d3E4Q9pi/+5McQ==
"@docusaurus/theme-search-algolia@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.3.tgz#32d4cbefc3deba4112068fbdb0bde11ac51ece53"
integrity sha512-jziq4f6YVUB5hZOB85ELATwnxBz/RmSLD3ksGQOLDPKVzat4pmI8tddNWtriPpxR04BNT+ZfpPUMFkNFetSW1Q==
dependencies:
"@docsearch/react" "^3.1.1"
"@docusaurus/core" "2.4.1"
"@docusaurus/logger" "2.4.1"
"@docusaurus/plugin-content-docs" "2.4.1"
"@docusaurus/theme-common" "2.4.1"
"@docusaurus/theme-translations" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/utils-validation" "2.4.1"
"@docusaurus/core" "2.4.3"
"@docusaurus/logger" "2.4.3"
"@docusaurus/plugin-content-docs" "2.4.3"
"@docusaurus/theme-common" "2.4.3"
"@docusaurus/theme-translations" "2.4.3"
"@docusaurus/utils" "2.4.3"
"@docusaurus/utils-validation" "2.4.3"
algoliasearch "^4.13.1"
algoliasearch-helper "^3.10.0"
clsx "^1.2.1"
@ -1618,18 +1618,18 @@
tslib "^2.4.0"
utility-types "^3.10.0"
"@docusaurus/theme-translations@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.4.1.tgz#4d49df5865dae9ef4b98a19284ede62ae6f98726"
integrity sha512-T1RAGP+f86CA1kfE8ejZ3T3pUU3XcyvrGMfC/zxCtc2BsnoexuNI9Vk2CmuKCb+Tacvhxjv5unhxXce0+NKyvA==
"@docusaurus/theme-translations@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-2.4.3.tgz#91ac73fc49b8c652b7a54e88b679af57d6ac6102"
integrity sha512-H4D+lbZbjbKNS/Zw1Lel64PioUAIT3cLYYJLUf3KkuO/oc9e0QCVhIYVtUI2SfBCF2NNdlyhBDQEEMygsCedIg==
dependencies:
fs-extra "^10.1.0"
tslib "^2.4.0"
"@docusaurus/types@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.4.1.tgz#d8e82f9e0f704984f98df1f93d6b4554d5458705"
integrity sha512-0R+cbhpMkhbRXX138UOc/2XZFF8hiZa6ooZAEEJFp5scytzCw4tC1gChMFXrpa3d2tYE6AX8IrOEpSonLmfQuQ==
"@docusaurus/types@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-2.4.3.tgz#4aead281ca09f721b3c0a9b926818450cfa3db31"
integrity sha512-W6zNLGQqfrp/EoPD0bhb9n7OobP+RHpmvVzpA+Z/IuU3Q63njJM24hmT0GYboovWcDtFmnIJC9wcyx4RVPQscw==
dependencies:
"@types/history" "^4.7.11"
"@types/react" "*"
@ -1640,30 +1640,30 @@
webpack "^5.73.0"
webpack-merge "^5.8.0"
"@docusaurus/utils-common@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.4.1.tgz#7f72e873e49bd5179588869cc3ab7449a56aae63"
integrity sha512-bCVGdZU+z/qVcIiEQdyx0K13OC5mYwxhSuDUR95oFbKVuXYRrTVrwZIqQljuo1fyJvFTKHiL9L9skQOPokuFNQ==
"@docusaurus/utils-common@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-2.4.3.tgz#30656c39ef1ce7e002af7ba39ea08330f58efcfb"
integrity sha512-/jascp4GbLQCPVmcGkPzEQjNaAk3ADVfMtudk49Ggb+131B1WDD6HqlSmDf8MxGdy7Dja2gc+StHf01kiWoTDQ==
dependencies:
tslib "^2.4.0"
"@docusaurus/utils-validation@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.4.1.tgz#19959856d4a886af0c5cfb357f4ef68b51151244"
integrity sha512-unII3hlJlDwZ3w8U+pMO3Lx3RhI4YEbY3YNsQj4yzrkZzlpqZOLuAiZK2JyULnD+TKbceKU0WyWkQXtYbLNDFA==
"@docusaurus/utils-validation@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-2.4.3.tgz#8122c394feef3e96c73f6433987837ec206a63fb"
integrity sha512-G2+Vt3WR5E/9drAobP+hhZQMaswRwDlp6qOMi7o7ZypB+VO7N//DZWhZEwhcRGepMDJGQEwtPv7UxtYwPL9PBw==
dependencies:
"@docusaurus/logger" "2.4.1"
"@docusaurus/utils" "2.4.1"
"@docusaurus/logger" "2.4.3"
"@docusaurus/utils" "2.4.3"
joi "^17.6.0"
js-yaml "^4.1.0"
tslib "^2.4.0"
"@docusaurus/utils@2.4.1":
version "2.4.1"
resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.4.1.tgz#9c5f76eae37b71f3819c1c1f0e26e6807c99a4fc"
integrity sha512-1lvEZdAQhKNht9aPXPoh69eeKnV0/62ROhQeFKKxmzd0zkcuE/Oc5Gpnt00y/f5bIsmOsYMY7Pqfm/5rteT5GA==
"@docusaurus/utils@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-2.4.3.tgz#52b000d989380a2125831b84e3a7327bef471e89"
integrity sha512-fKcXsjrD86Smxv8Pt0TBFqYieZZCPh4cbf9oszUq/AMhZn3ujwpKaVYZACPX8mmjtYx0JOgNx52CREBfiGQB4A==
dependencies:
"@docusaurus/logger" "2.4.1"
"@docusaurus/logger" "2.4.3"
"@svgr/webpack" "^6.2.1"
escape-string-regexp "^4.0.0"
file-loader "^6.2.0"