Merge branch 'v1_0_0' into canary_1

This commit is contained in:
Michael Quigley 2025-02-19 14:00:41 -05:00
commit e2687e5790
No known key found for this signature in database
GPG Key ID: 9B60314A9DD20A62
1059 changed files with 46395 additions and 52296 deletions

View File

@ -1,3 +1,6 @@
[flake8]
max-line-length = 120
exclude = zrok_api, build
exclude =
./sdk/python/sdk/zrok/zrok_api/**,
./build/**

View File

@ -1,9 +1,9 @@
Thank you for taking the time to reach out regarding zrok!
*** IMPORTANT: THIS ISSUE DATABASE IS NOT FOR SUPPORT ***
If you think you have found a bug in zrok, or you need help with a specific issue, please reach out for support on the OpenZiti Discourse group at:
https://openziti.discourse.group/
There is a zrok topic available there. The entire zrok and OpenZiti team are monitoring that forum. They're not monitoring this issue database. If you decide to open an issue here anyway, we're probably still going to guide you to the Discourse forum to assist you. Going there first will get you help faster. :-)
There is a zrok topic available there. You can use your GitHub credentials to log in. The entire zrok and OpenZiti team are monitoring that forum. They're not monitoring this issue database. If you decide to open an issue here anyway, we're probably still going to guide you to the Discourse forum to assist you. Going there first will get you help faster. :-)
This issue database is for vetted roadmap items and confirmed bugs within the core open-source portion of zrok.

View File

@ -5,7 +5,26 @@ on:
types: [released]
jobs:
enforce_stable_semver:
name: Require Stable Release Semver
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.parse.outputs.version }}
steps:
- name: Parse Release Version
id: parse
shell: bash
run: |
if [[ "${GITHUB_REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME} is a stable release semver ref"
echo "version=${GITHUB_REF_NAME#v}" | tee -a $GITHUB_OUTPUT
else
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME} is not a stable release semver ref" >&2
exit 1
fi
build_wheels:
needs: enforce_stable_semver
defaults:
run:
working-directory: sdk/python/sdk/zrok
@ -45,7 +64,7 @@ jobs:
name: zrok_sdk_${{ matrix.spec.target }}
path: ${{ github.workspace }}/sdk/python/sdk/zrok/dist/*
publish:
publish-testpypi:
runs-on: ubuntu-20.04
needs: [ build_wheels ]
permissions:
@ -54,16 +73,10 @@ jobs:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: ./download
path: ./dist
merge-multiple: true
pattern: zrok_sdk_*
- name: check
run: |
ls -lR ./download/
mkdir dist
cp ./download/* ./dist/
- name: Publish wheels (TestPYPI)
uses: pypa/gh-action-pypi-publish@release/v1
with:
@ -72,6 +85,19 @@ jobs:
skip-existing: true
verbose: true
publish-pypi:
runs-on: ubuntu-20.04
needs: [ publish-testpypi ]
permissions:
id-token: write
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: ./dist
merge-multiple: true
pattern: zrok_sdk_*
- name: Publish wheels (PyPI)
uses: pypa/gh-action-pypi-publish@release/v1
with:

View File

@ -29,19 +29,29 @@ jobs:
- name: setup-node
uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: 20.x
- name: install ui node modules
shell: bash
run: npm install
working-directory: ui
- name: build node ui
- name: build ui
shell: bash
run: npm run build
working-directory: ui
env:
CI: "true"
- name: install agent ui node modules
shell: bash
run: npm install
working-directory: agent/agentUi
- name: build agent ui
shell: bash
run: npm run build
working-directory: agent/agentUi
- name: go install
shell: bash

View File

@ -5,7 +5,26 @@ on:
types: [released]
jobs:
enforce_stable_semver:
name: Require Stable Release Semver
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.parse.outputs.version }}
steps:
- name: Parse Release Version
id: parse
shell: bash
run: |
if [[ "${GITHUB_REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME} is a stable release semver ref"
echo "version=${GITHUB_REF_NAME#v}" | tee -a $GITHUB_OUTPUT
else
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME} is not a stable release semver ref" >&2
exit 1
fi
update-brew:
needs: enforce_stable_semver
if: github.repository_owner == 'openziti'
runs-on: ubuntu-latest
steps:

View File

@ -2,13 +2,34 @@ name: Build/Release Node SDK
on:
release:
types: [ published ]
types: [ released ]
pull_request:
branches: [ main ]
jobs:
enforce_stable_semver:
name: Require Stable Release Semver
if: github.event.action == 'released'
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.parse.outputs.version }}
steps:
- name: Parse Release Version
id: parse
shell: bash
run: |
if [[ "${GITHUB_REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME} is a stable release semver ref"
echo "version=${GITHUB_REF_NAME#v}" | tee -a $GITHUB_OUTPUT
else
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME} is not a stable release semver ref" >&2
exit 1
fi
build:
needs: enforce_stable_semver
if: always()
name: Build for Node-${{ matrix.node_ver }} ${{ matrix.config.target }}/${{ matrix.config.arch }}
runs-on: ${{ matrix.config.os }}
@ -69,4 +90,3 @@ jobs:
npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@ -0,0 +1,108 @@
name: Promote Downstream Releases
on:
# may be triggered manually on a release tag that represents a prerelease to promote it to a release in the downstream package repositories and Docker Hub
workflow_dispatch:
# automatically trigger if an existing GitHub release is marked "latest"
release:
types: [released] # this release event activity type excludes prereleases
# cancel older, redundant runs of same workflow on same branch
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
jobs:
enforce_stable_semver:
name: Require Stable Release Semver
runs-on: ubuntu-24.04
outputs:
version: ${{ steps.parse.outputs.version }}
steps:
- name: Parse Release Version
id: parse
shell: bash
run: |
if [[ "${GITHUB_REF_NAME}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME} is a stable release semver ref"
echo "version=${GITHUB_REF_NAME#v}" | tee -a $GITHUB_OUTPUT
else
echo "GITHUB_REF_NAME=${GITHUB_REF_NAME} is not a stable release semver ref" >&2
exit 1
fi
promote_docker:
name: Tag Container Image ${{ matrix.image.repo }}:latest
needs: enforce_stable_semver
runs-on: ubuntu-24.04
strategy:
fail-fast: true
matrix:
image:
- repo: ${{ vars.ZROK_CONTAINER_IMAGE_REPO || 'docker.io/openziti/zrok' }}
steps:
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKER_HUB_API_USER || secrets.DOCKER_HUB_API_USER }}
password: ${{ secrets.DOCKER_HUB_API_TOKEN }}
- name: Tag Latest
shell: bash
run: >
docker buildx imagetools create --tag
${{ matrix.image.repo }}:latest
${{ matrix.image.repo }}:${{ needs.enforce_stable_semver.outputs.version }}
promote_artifactory:
name: Promote ${{ matrix.package_name }}-${{ matrix.arch.rpm }}.${{ matrix.packager }}
needs: enforce_stable_semver
strategy:
fail-fast: true
matrix:
package_name:
- zrok
- zrok-share
arch:
- deb: amd64
rpm: x86_64
- deb: arm64
rpm: aarch64
- deb: armhf
rpm: armv7hl
packager:
- rpm
- deb
runs-on: ubuntu-24.04
env:
ZITI_DEB_TEST_REPO: ${{ vars.ZITI_DEB_TEST_REPO || 'zitipax-openziti-deb-test' }}
ZITI_RPM_TEST_REPO: ${{ vars.ZITI_RPM_TEST_REPO || 'zitipax-openziti-rpm-test' }}
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' }}
steps:
- name: Configure jFrog CLI
uses: jfrog/setup-jfrog-cli@v4
env:
JF_ENV_1: ${{ secrets.ZITI_ARTIFACTORY_CLI_CONFIG_PACKAGE_UPLOAD }}
- name: Copy RPM from test repo to stable repo with jFrog CLI
if: matrix.packager == 'rpm'
shell: bash
run: >
jf rt copy
--recursive=false
--flat=true
--fail-no-op=true
${{ env.ZITI_RPM_TEST_REPO }}/redhat/${{ matrix.arch.rpm }}/${{ matrix.package_name }}-${{ needs.enforce_stable_semver.outputs.version }}-1.${{ matrix.arch.rpm }}.rpm
${{ env.ZITI_RPM_PROD_REPO }}/redhat/${{ matrix.arch.rpm }}/
- name: Copy DEB from test repo to stable repo with jFrog CLI
if: matrix.packager == 'deb'
shell: bash
run: >
jf rt copy
--recursive=false
--flat=true
--fail-no-op=true
${{ env.ZITI_DEB_TEST_REPO }}/pool/${{ matrix.package_name }}/${{ matrix.arch.deb }}/${{ matrix.package_name }}_${{ needs.enforce_stable_semver.outputs.version }}-1_${{ matrix.arch.deb }}.deb
${{ env.ZITI_DEB_PROD_REPO }}/pool/${{ matrix.package_name }}/${{ matrix.arch.deb }}/

View File

@ -1,55 +1,40 @@
name: Publish Docker Images
on:
workflow_dispatch:
workflow_call:
inputs:
zrok-version:
description: zrok release tag to publish as a Docker image
description: Image tag to publish for zrok container images
type: string
required: true
release:
types:
- released # excludes "prereleased" which is included in "published" to
# avoid prematurely releasing semver tagged container images
jobs:
publish-docker-images:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
env:
RELEASE_REF: ${{ inputs.zrok-version || github.ref }}
RELEASE_REF: ${{ inputs.zrok-version }}
steps:
# compose the semver string without leading "refs/tags" or "v" so we can predict the
# release artifact filename
- name: Set zrok Version Semver from Tag Ref
id: semver
run: |
zrok_semver=${RELEASE_REF#refs/tags/}
echo "zrok_semver=${zrok_semver#v}" | tee -a $GITHUB_OUTPUT
echo "zrok_semver=${RELEASE_REF#v}" | tee -a $GITHUB_OUTPUT
- name: Checkout Workspace
uses: actions/checkout@v4
- name: Create the Release Arch Dirs
run: |
for TGZ in dist/{amd,arm}64/linux/; do
mkdir -pv ${TGZ}
done
- name: Download Linux AMD64 Release Artifact
uses: dsaltares/fetch-gh-release-asset@1.1.2
uses: actions/download-artifact@v4
with:
version: tags/v${{ steps.semver.outputs.zrok_semver }}
file: zrok.*_linux_amd64.tar.gz
regex: true
target: dist/amd64/linux/zrok_linux_amd64.tar.gz
name: release-builds-linux-amd64
path: dist/amd64/linux
- name: Download Linux ARM64 Release Artifact
uses: dsaltares/fetch-gh-release-asset@1.1.2
uses: actions/download-artifact@v4
with:
version: tags/v${{ steps.semver.outputs.zrok_semver }}
file: zrok.*_linux_arm64.tar.gz
regex: true
target: dist/arm64/linux/zrok_linux_arm64.tar.gz
name: release-builds-linux-arm64
path: dist/arm64/linux
- name: Unpack the Release Artifacts
run: |
@ -79,7 +64,6 @@ jobs:
id: tagprep_cli
run: |
DOCKER_TAGS="${ZROK_CONTAINER_IMAGE_REPO}:${ZROK_CONTAINER_IMAGE_TAG}"
DOCKER_TAGS+=",${ZROK_CONTAINER_IMAGE_REPO}:latest"
echo "DOCKER_TAGS=${DOCKER_TAGS}" | tee -a $GITHUB_OUTPUT
# this is the CLI image with the Linux binary for each

View File

@ -1,4 +1,4 @@
name: Release
name: Pre-Release
on:
push:
@ -10,16 +10,37 @@ 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' }}
ZITI_DEB_TEST_REPO: ${{ vars.ZITI_DEB_TEST_REPO || 'zitipax-openziti-deb-test' }}
ZITI_RPM_TEST_REPO: ${{ vars.ZITI_RPM_TEST_REPO || 'zitipax-openziti-rpm-test' }}
JFROG_CLI_VERSION: ${{ vars.JFROG_CLI_VERSION || '2.50.4' }}
jobs:
build-linux-amd64:
runs-on: ubuntu-20.04
build-linux:
name: build-linux-${{ matrix.arch.goreleaser }}
needs:
- build-darwin
- build-windows
runs-on: ubuntu-22.04 # oldest Docker host runner for broadest kernel, syscall, ABI support
container: openziti/ziti-builder:v2 # v2 is based on ubuntu focal 20.04 for broadest glibc support
strategy:
matrix:
arch:
- goreleaser: amd64
deb: amd64
rpm: x86_64
gcc: gcc g++
- goreleaser: arm64
deb: arm64
rpm: aarch64
gcc: gcc-aarch64-linux-gnu
- goreleaser: armhf
deb: armhf
rpm: armv7hl
gcc: gcc-arm-linux-gnueabihf
steps:
- run: sudo apt update
- run: sudo apt-get install gcc-multilib g++-multilib
# skipped because ziti-builder image provides the multi-arch, multi-lib build toolchain
# - run: apt-get update
# - run: apt-get --yes --quiet install ${{ matrix.arch.gcc }}
- uses: actions/checkout@v4
with:
@ -44,73 +65,11 @@ jobs:
env:
CI: "true"
- uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: '~> v2'
args: release --skip=publish --config .goreleaser-linux-amd64.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v4
with:
name: release-builds-linux-amd64
path: ./dist/*.gz
- name: Configure jFrog CLI
uses: jfrog/setup-jfrog-cli@v4
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:
- run: sudo apt update
- run: sudo apt-get install gcc-aarch64-linux-gnu
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
cache: true
- uses: actions/setup-node@v4
with:
node-version: 18.x
- run: npm install
working-directory: ui
working-directory: agent/agentUi
- run: npm run build
working-directory: ui
working-directory: agent/agentUi
env:
CI: "true"
@ -118,13 +77,13 @@ jobs:
with:
distribution: goreleaser
version: '~> v2'
args: release --skip=publish --config .goreleaser-linux-arm64.yml
args: release --skip=publish --config .goreleaser-linux-${{ matrix.arch.goreleaser }}.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v4
with:
name: release-builds-linux-arm64
name: release-builds-linux-${{ matrix.arch.goreleaser }}
path: ./dist/*.gz
- name: Configure jFrog CLI
@ -134,95 +93,77 @@ jobs:
env:
JF_ENV_1: ${{ secrets.ZITI_ARTIFACTORY_CLI_CONFIG_PACKAGE_UPLOAD }}
- name: Upload RPM to Artifactory release repo
- name: Upload RPM to Artifactory pre-release repo
shell: bash
env:
ARCH: ${{ matrix.arch.rpm }}
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/
set -o xtrace
shopt -s nullglob
SEMVER=${GITHUB_REF_NAME#v}
SEMVER_CORE=${SEMVER%%-*}
if [[ "$SEMVER_CORE" == ${SEMVER#*-} ]]; then
SEMVER_PRE="" # no semver pre-release suffix
else
SEMVER_PRE=${SEMVER#*-}
fi
for PAX in zrok{,-share}; do
_pattern="./dist/${PAX}-${SEMVER_CORE}${SEMVER_PRE:+~${SEMVER_PRE}}*.${ARCH}.rpm"
if ! compgen -G "$_pattern" > /dev/null; then
echo "ERROR: No RPM files found matching pattern '${_pattern}'" >&2
ls -1 ./dist/
exit 1
fi
_rpms=( $_pattern )
if [[ ${#_rpms[@]} -ne 1 ]]; then
echo "ERROR: Failed to find exactly one RPM file, got: '${_rpms[@]}'" >&2
exit 1
fi
echo "INFO: Uploading ${_rpms[0]}"
jf rt upload \
--recursive=false \
--flat=true \
--fail-no-op=true \
"${_rpms[0]}" \
${{ env.ZITI_RPM_TEST_REPO }}/redhat/${ARCH}/
done
- name: Upload DEB to Artifactory release repo
- name: Upload DEB to Artifactory pre-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:
- run: sudo apt update
- run: sudo apt-get install gcc-arm-linux-gnueabihf
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: actions/setup-go@v5
with:
go-version-file: ./go.mod
cache: true
- uses: actions/setup-node@v4
with:
node-version: 18.x
- run: npm install
working-directory: ui
- run: npm run build
working-directory: ui
env:
CI: "true"
- uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
version: '~> v2'
args: release --skip=publish --config .goreleaser-linux-armhf.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/upload-artifact@v4
with:
name: release-builds-linux-arm
path: ./dist/*.gz
- name: Configure jFrog CLI
uses: jfrog/setup-jfrog-cli@v4
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
ARCH: ${{ matrix.arch.deb }}
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
set -o xtrace
shopt -s nullglob
SEMVER=${GITHUB_REF_NAME#v}
SEMVER_CORE=${SEMVER%%-*}
if [[ "$SEMVER_CORE" == ${SEMVER#*-} ]]; then
SEMVER_PRE="" # no semver pre-release suffix
else
SEMVER_PRE=${SEMVER#*-}
fi
for PAX in zrok{,-share}; do
_pattern="./dist/${PAX}_${SEMVER_CORE}${SEMVER_PRE:+~${SEMVER_PRE}}*_${ARCH}.deb"
if ! compgen -G "$_pattern" > /dev/null; then
echo "ERROR: No DEB files found matching pattern '${_pattern}'" >&2
ls -1 ./dist/
exit 1
fi
_debs=( $_pattern )
if [[ ${#_debs[@]} -ne 1 ]]; then
echo "ERROR: Failed to match exactly one DEB file, got: '${_debs[@]}'" >&2
exit 1
fi
- 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/
echo "INFO: Uploading ${_debs[0]}"
jf rt upload \
--recursive=false \
--flat=true \
--fail-no-op=true \
--deb=debian/main/${ARCH} \
"${_debs[0]}" \
${{ env.ZITI_DEB_TEST_REPO }}/pool/${PAX}/${ARCH}/
done
build-darwin:
@ -258,6 +199,14 @@ jobs:
env:
CI: "true"
- run: npm install
working-directory: agent/agentUi
- run: npm run build
working-directory: agent/agentUi
env:
CI: "true"
- uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
@ -303,6 +252,14 @@ jobs:
env:
CI: "true"
- run: npm install
working-directory: agent/agentUi
- run: npm run build
working-directory: agent/agentUi
env:
CI: "true"
- uses: goreleaser/goreleaser-action@v6
with:
distribution: goreleaser
@ -316,23 +273,20 @@ jobs:
name: release-builds-windows
path: ./dist/*.gz
publish-release:
# allow skipped but not failed
if: ${{
!cancelled()
&& (needs.build-linux-amd64.result == 'success')
&& (needs.build-linux-arm.result == 'success')
&& (needs.build-linux-arm64.result == 'success')
&& (needs.build-darwin.result == 'success' || needs.build-darwin.result == 'skipped')
&& (needs.build-windows.result == 'success' || needs.build-windows.result == 'skipped')
}}
call-publish-docker-images:
name: Publish Release Docker Images
needs:
- build-linux-amd64
- build-linux-arm
- build-linux-arm64
- build-linux
- build-darwin
- build-windows
uses: ./.github/workflows/publish-docker-images.yml
secrets: inherit
with:
zrok-version: ${{ github.ref_name }}
draft-release:
runs-on: ubuntu-latest
needs: call-publish-docker-images
steps:
- uses: actions/checkout@v4

View File

@ -1,5 +1,56 @@
# CHANGELOG
## v1.0.0
MAJOR RELEASE: zrok reaches version 1.0.0!
FEATURE: Completely redesigned web interface ("API Console"). New implementation provides a dual-mode interface supporting an improved visual network navigator and also a "tabular" view, which provides a more traditional "data" view. New stack built using vite, React, and TypeScript (https://github.com/openziti/zrok/issues/724)
FEATURE: New "zrok Agent", a background manager process for your zrok environments, which allows you to easily manage and work with multiple `zrok share` and `zrok access` processes. New `--subordinate` flag added to `zrok share [public|private|reserved]` and `zrok access private` to operate in a mode that allows an Agent to manage shares and accesses (https://github.com/openziti/zrok/issues/463)
FEATURE: New "zrok Agent UI" a web-based user interface for the zrok Agent, which allows creating and releasing shares and accesses through a web browser. This is just an initial chunk of the new Agent UI, and is considered a "minimum viable" version of this interface (https://github.com/openziti/zrok/issues/221)
FEATURE: `zrok share [public|private|reserved]` and `zrok access private` now auto-detect if the zrok Agent is running in an environment and will automatically service share and access requests through the Agent, rather than in-process if the Agent is running. If the Agent is not running, operation remains as it was in `v0.4.x` and the share or access is handled in-process. New `--force-agent` and `--force-local` flags exist to skip Agent detection and manually select an operating mode (https://github.com/openziti/zrok/issues/751)
FEATURE `zrok access private` supports a new `--auto` mode, which can automatically find an available open address/port to bind the frontend listener on. Also includes `--auto-address`, `--auto-start-port`, and `--auto-end-port` features with sensible defaults. Supported by both the agent and local operating modes (https://github.com/openziti/zrok/issues/780)
FEATURE `zrok rebase` command allows "rebasing" an enabled environment onto a different API endpoint. This is useful for migrating already-enabled environments between endpoints supporting different zrok versions (https://github.com/openziti/zrok/issues/869)
CHANGE: Refactored API implementation. Cleanup, lint removal, additional data elements added, unused data removed (https://github.com/openziti/zrok/issues/834)
CHANGE: Deprecated the `passwords` configuration stanza. The zrok controller and API console now use a hard-coded set of (what we believe to be) reasonable assumptions about password quality (https://github.com/openziti/zrok/issues/834)
CHANGE: The protocol for determining valid client versions has been changed. Previously a zrok client would do a `GET` against the `/api/v1/version` endpoint and do a local version string comparison (as a normal precondition to any API call) to see if the controller version matched. The protocol has been amended so that any out-of-date client using the old protocol will receive a version string indicating that they need to uprade their client. New clients will do a `POST` against the `/api/v1/version` endpoint, posting their client version, and the server will check for compatibility. Does not change the security posture in any significant way, but gives more flexibility on the server side for managing client compatibility. Provides a better, cleared out-of-date error message for old clients when accessing `v1.0.0`+ (https://github.com/openziti/zrok/issues/859)
## v0.4.49
FIX: Pre-releases are no longer uploaded to the stable Linux package repo.
CHANGE: Pre-releases are uploaded to the pre-release Linux package repo and Docker Hub for testing. [RELEASING.md](./RELEASING.md) describes releaser steps and the events they trigger.
CHANGE: Linux release binaries are now built on the ziti-builder container image based on Ubuntu Focal 20.04 to preserve backward compatibility as the ubuntu-20.04 GitHub runner is end of life.
## v0.4.48
FEATURE: The controller configuration now supports a `disable_auto_migration` boolean in the `store` stanza. When set to `true`, the controller will not attempt to auto-migrate (or otherwise validate the migration state) of the underlying database. Leaving `disable_auto_migration` out, or setting it to false will retain the default behavior of auto-migrating when starting the zrok controller. The `zrok admin migrate` command will still perform a migration regardless of how this setting is configured in the controller configuration (https://github.com/openziti/zrok/issues/866)
FIX: the Python SDK erroneously assumed the enabled zrok environment contained a config.json file, and was changed to only load it if the file was present (https://github.com/openziti/zrok/pull/853/).
## v0.4.47
CHANGE: the Docker instance will wait for the ziti container healthy status (contribution from Ben Wong @bwong365 - https://github.com/openziti/zrok/pull/790)
CHANGE: Document solving the DNS propagation timeout for Docker instances that are using Caddy to manage the wildcard certificate.
CHANGE: Add usage hint in `zrok config get --help` to clarify how to list all valid `configName` and their current values by running `zrok status`.
CHANGE: The Python SDK's `Overview()` function was refactored as a class method (https://github.com/openziti/zrok/pull/846).
FEATURE: The Python SDK now includes a `ProxyShare` class providing an HTTP proxy for public and private shares and a
Jupyter notebook example (https://github.com/openziti/zrok/pull/847).
FIX: PyPi publishing was failing due to a CI issue (https://github.com/openziti/zrok/issues/849)
## v0.4.46
FEATURE: Linux service template for systemd user units (https://github.com/openziti/zrok/pull/818)

View File

@ -1,17 +1,37 @@
# Releasing zrok
## Manual Steps
## Semantic Versioning
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.
This project uses semantic versioning. See [here](https://semver.org/) for more information.
## Automated Steps
Release tags like `v3.2.1` are eligible for promotion to stable status in GitHub and downstream distribution channels.
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.
Pre-release tags like `v3.2.1-rc1` (with a semver hyphenated pre-release suffix) are published in GitHub as pre-releases, and are blocked from promotion to downstream distribution channels if they are marked "stable" by mistake and the GitHub "released" event fires.
Pre-release version strings must contain exactly one hyphen, and may not contain an underscore.
## How to Trigger Release Automation
> [!NOTE]
> Each trigger is outlined separately, but some may occur simultaneously, e.g., when a draft release is published as stable rather than first publishing it as a pre-release, or a pre-release is promoted to stable and marked as latest at the same time.
1. Push a tag to GitHub like `v*.*.*` to trigger **the pre-release workflow**. Wait for this workflow to complete before marking the release stable (`isPrerelease: false`).
1. Linux packages are uploaded to Artifactory as pre-releases.
1. Docker images are uploaded to Docker Hub as pre-releases.
1. A release is drafted in GitHub.
1. Edit the draft and publish the release as a pre-release (`isPrerelease: true`).
1. The one-time GitHub "published" event fires, and binaries are available in GitHub.
1. If the release does not have a pre-release suffix, mark it as stable by un-checking (`isPrerelease: false`).
1. The one-time GitHub "released" event fires.
1. Linux packages are promoted to "stable" in Artifactory.
1. Docker images are promoted to `:latest` in Docker Hub.
1. Homebrew formulae are built and released.
1. Python wheels are built and released to PyPi.
1. Node.js packages are built and released to NPM.
1. Edit the stable release to mark it as latest.
1. https://docs.zrok.io/docs/guides/install/ always serves the "latest" stable version via GitHub binary download URLs.
## Rolling Back Downstreams
The concepts, tools, and procedures for managing existing downstream artifacts in Artifactory and Docker Hub are identical for zrok and ziti. Here's the [RELEASING.md document for ziti](https://github.com/openziti/ziti/blob/main/RELEASING.md#rolling-back-downstreams).

View File

@ -1,11 +1,3 @@
# Security Policy
## Supported Versions
Until v1.0.0 or higher is reached, only the most recent version is supported. After v1.0.0 a new version support statement will be released.
## Reporting a Vulnerability
If you have an issue that is not a sensitive security issue, please submit your issue via the GitHub issue tracker on either the main repository.
If you have a sensitive security issue or are unsure if it is sensitive, please email it to: security@openziti.org
Please refer to the [openziti-security repository](https://github.com/openziti/openziti-security) for details of the security policies and processes for this repository.

30
agent/access.go Normal file
View File

@ -0,0 +1,30 @@
package agent
import (
"github.com/michaelquigley/pfxlog"
"github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
)
type access struct {
frontendToken string
token string
bindAddress string
autoMode bool
autoAddress string
autoStartPort uint16
autoEndPort uint16
responseHeaders []string
process *proctree.Child
sub *subordinate.MessageHandler
agent *Agent
}
func (a *access) monitor() {
if err := proctree.WaitChild(a.process); err != nil {
pfxlog.ChannelLogger(a.token).Error(err)
}
a.agent.rmAccess <- a
}

93
agent/accessPrivate.go Normal file
View File

@ -0,0 +1,93 @@
package agent
import (
"context"
"errors"
"fmt"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/environment"
"github.com/sirupsen/logrus"
"os"
)
func (i *agentGrpcImpl) AccessPrivate(_ context.Context, req *agentGrpc.AccessPrivateRequest) (*agentGrpc.AccessPrivateResponse, error) {
root, err := environment.LoadRoot()
if err != nil {
return nil, err
}
if !root.IsEnabled() {
return nil, errors.New("unable to load environment; did you 'zrok enable'?")
}
accCmd := []string{os.Args[0], "access", "private", "--subordinate", "-b", req.BindAddress, req.Token}
if req.AutoMode {
accCmd = append(accCmd, "--auto", "--auto-address", req.AutoAddress, "--auto-start-port", fmt.Sprintf("%v", req.AutoStartPort))
accCmd = append(accCmd, "--auto-end-port", fmt.Sprintf("%v", req.AutoEndPort))
}
logrus.Info(accCmd)
acc := &access{
token: req.Token,
bindAddress: req.BindAddress,
autoMode: req.AutoMode,
autoAddress: req.AutoAddress,
autoStartPort: uint16(req.AutoStartPort),
autoEndPort: uint16(req.AutoEndPort),
responseHeaders: req.ResponseHeaders,
sub: subordinate.NewMessageHandler(),
agent: i.agent,
}
acc.sub.MessageHandler = func(msg subordinate.Message) {
logrus.Info(msg)
}
var bootErr error
acc.sub.BootHandler = func(msgType string, msg subordinate.Message) {
switch msgType {
case subordinate.BootMessage:
if v, found := msg["frontend_token"]; found {
if str, ok := v.(string); ok {
acc.frontendToken = str
}
}
if v, found := msg["bind_address"]; found {
if sr, ok := v.(string); ok {
acc.bindAddress = sr
}
}
case subordinate.ErrorMessage:
if v, found := msg[subordinate.ErrorMessage]; found {
if str, ok := v.(string); ok {
bootErr = errors.New(str)
}
}
}
}
acc.sub.MalformedHandler = func(msg subordinate.Message) {
logrus.Error(msg)
}
logrus.Infof("executing '%v'", accCmd)
acc.process, err = proctree.StartChild(acc.sub.Tail, accCmd...)
if err != nil {
return nil, err
}
<-acc.sub.BootComplete
if bootErr == nil {
go acc.monitor()
i.agent.addAccess <- acc
return &agentGrpc.AccessPrivateResponse{FrontendToken: acc.frontendToken}, nil
} else {
if err := proctree.WaitChild(acc.process); err != nil {
logrus.Errorf("error joining: %v", err)
}
return nil, fmt.Errorf("unable to start access: %v", bootErr)
}
}

197
agent/agent.go Normal file
View File

@ -0,0 +1,197 @@
package agent
import (
"context"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/agentUi"
"github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/environment/env_core"
"github.com/openziti/zrok/sdk/golang/sdk"
"github.com/openziti/zrok/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"net"
"net/http"
"os"
)
type Agent struct {
cfg *AgentConfig
httpEndpoint string
root env_core.Root
agentSocket string
shares map[string]*share
addShare chan *share
rmShare chan *share
accesses map[string]*access
addAccess chan *access
rmAccess chan *access
}
func NewAgent(cfg *AgentConfig, root env_core.Root) (*Agent, error) {
if !root.IsEnabled() {
return nil, errors.Errorf("unable to load environment; did you 'zrok enable'?")
}
return &Agent{
cfg: cfg,
root: root,
shares: make(map[string]*share),
addShare: make(chan *share),
rmShare: make(chan *share),
accesses: make(map[string]*access),
addAccess: make(chan *access),
rmAccess: make(chan *access),
}, nil
}
func (a *Agent) Run() error {
logrus.Infof("started")
if err := proctree.Init("zrok Agent"); err != nil {
return err
}
agentSocket, err := a.root.AgentSocket()
if err != nil {
return err
}
l, err := net.Listen("unix", agentSocket)
if err != nil {
return err
}
a.agentSocket = agentSocket
go a.manager()
go a.gateway(a.cfg)
srv := grpc.NewServer()
agentGrpc.RegisterAgentServer(srv, &agentGrpcImpl{agent: a})
if err := srv.Serve(l); err != nil {
return err
}
return nil
}
func (a *Agent) Shutdown() {
logrus.Infof("stopping")
if err := os.Remove(a.agentSocket); err != nil {
logrus.Warnf("unable to remove agent socket: %v", err)
}
for _, shr := range a.shares {
logrus.Debugf("stopping share '%v'", shr.token)
a.rmShare <- shr
}
for _, acc := range a.accesses {
logrus.Debugf("stopping access '%v'", acc.token)
a.rmAccess <- acc
}
}
func (a *Agent) Config() *AgentConfig {
return a.cfg
}
func (a *Agent) gateway(cfg *AgentConfig) {
logrus.Info("started")
defer logrus.Warn("exited")
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
endpoint := "unix:" + a.agentSocket
logrus.Debugf("endpoint: '%v'", endpoint)
if err := agentGrpc.RegisterAgentHandlerFromEndpoint(ctx, mux, "unix:"+a.agentSocket, opts); err != nil {
logrus.Fatalf("unable to register gateway: %v", err)
}
listener, err := util.AutoListener("tcp", cfg.ConsoleAddress, cfg.ConsoleStartPort, cfg.ConsoleEndPort)
if err != nil {
logrus.Fatalf("unable to create a listener: %v", err)
}
a.httpEndpoint = listener.Addr().String()
if err := http.Serve(listener, agentUi.Middleware(mux)); err != nil {
logrus.Error(err)
}
}
func (a *Agent) manager() {
logrus.Info("started")
defer logrus.Warn("exited")
for {
select {
case inShare := <-a.addShare:
logrus.Infof("adding new share '%v'", inShare.token)
a.shares[inShare.token] = inShare
case outShare := <-a.rmShare:
if shr, found := a.shares[outShare.token]; found {
logrus.Infof("removing share '%v'", shr.token)
if err := proctree.StopChild(shr.process); err != nil {
logrus.Errorf("error stopping share '%v': %v", shr.token, err)
}
if err := proctree.WaitChild(shr.process); err != nil {
logrus.Errorf("error joining share '%v': %v", shr.token, err)
}
if !shr.reserved {
if err := a.deleteShare(shr.token); err != nil {
logrus.Errorf("error deleting share '%v': %v", shr.token, err)
}
}
delete(a.shares, shr.token)
} else {
logrus.Debug("skipping unidentified (orphaned) share removal")
}
case inAccess := <-a.addAccess:
logrus.Infof("adding new access '%v'", inAccess.frontendToken)
a.accesses[inAccess.frontendToken] = inAccess
case outAccess := <-a.rmAccess:
if acc, found := a.accesses[outAccess.frontendToken]; found {
logrus.Infof("removing access '%v'", acc.frontendToken)
if err := proctree.StopChild(acc.process); err != nil {
logrus.Errorf("error stopping access '%v': %v", acc.frontendToken, err)
}
if err := proctree.WaitChild(acc.process); err != nil {
logrus.Errorf("error joining access '%v': %v", acc.frontendToken, err)
}
if err := a.deleteAccess(acc.token, acc.frontendToken); err != nil {
logrus.Errorf("error deleting access '%v': %v", acc.frontendToken, err)
}
delete(a.accesses, acc.frontendToken)
} else {
logrus.Debug("skipping unidentified (orphaned) access removal")
}
}
}
}
func (a *Agent) deleteShare(token string) error {
logrus.Debugf("deleting share '%v'", token)
if err := sdk.DeleteShare(a.root, &sdk.Share{Token: token}); err != nil {
return err
}
return nil
}
func (a *Agent) deleteAccess(token, frontendToken string) error {
logrus.Debugf("deleting access '%v'", frontendToken)
if err := sdk.DeleteAccess(a.root, &sdk.Access{Token: frontendToken, ShareToken: token}); err != nil {
return err
}
return nil
}
type agentGrpcImpl struct {
agentGrpc.UnimplementedAgentServer
agent *Agent
}

View File

@ -0,0 +1,51 @@
package agentClient
import (
"context"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/build"
"github.com/openziti/zrok/environment/env_core"
"github.com/pkg/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/resolver"
"net"
"strings"
)
func NewClient(root env_core.Root) (client agentGrpc.AgentClient, conn *grpc.ClientConn, err error) {
agentSocket, err := root.AgentSocket()
if err != nil {
return nil, nil, err
}
opts := []grpc.DialOption{
grpc.WithContextDialer(func(_ context.Context, addr string) (net.Conn, error) {
return net.Dial("unix", addr)
}),
grpc.WithTransportCredentials(insecure.NewCredentials()),
}
resolver.SetDefaultScheme("passthrough")
conn, err = grpc.NewClient(agentSocket, opts...)
if err != nil {
return nil, nil, err
}
return agentGrpc.NewAgentClient(conn), conn, nil
}
func IsAgentRunning(root env_core.Root) (bool, error) {
client, conn, err := NewClient(root)
if err != nil {
return false, err
}
defer func() { _ = conn.Close() }()
resp, err := client.Version(context.Background(), &agentGrpc.VersionRequest{})
if err != nil {
return false, nil
}
if !strings.HasPrefix(resp.GetV(), build.Series) {
return false, errors.Errorf("agent reported version '%v'; we expected version '%v'", resp.GetV(), build.Series)
}
return true, nil
}

1625
agent/agentGrpc/agent.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,659 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: agent/agentGrpc/agent.proto
/*
Package agentGrpc is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package agentGrpc
import (
"context"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = metadata.Join
var (
filter_Agent_AccessPrivate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Agent_AccessPrivate_0(ctx context.Context, marshaler runtime.Marshaler, client AgentClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AccessPrivateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_AccessPrivate_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.AccessPrivate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Agent_AccessPrivate_0(ctx context.Context, marshaler runtime.Marshaler, server AgentServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq AccessPrivateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_AccessPrivate_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.AccessPrivate(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_Agent_ReleaseAccess_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Agent_ReleaseAccess_0(ctx context.Context, marshaler runtime.Marshaler, client AgentClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReleaseAccessRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_ReleaseAccess_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ReleaseAccess(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Agent_ReleaseAccess_0(ctx context.Context, marshaler runtime.Marshaler, server AgentServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReleaseAccessRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_ReleaseAccess_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ReleaseAccess(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_Agent_ReleaseShare_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Agent_ReleaseShare_0(ctx context.Context, marshaler runtime.Marshaler, client AgentClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReleaseShareRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_ReleaseShare_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ReleaseShare(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Agent_ReleaseShare_0(ctx context.Context, marshaler runtime.Marshaler, server AgentServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ReleaseShareRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_ReleaseShare_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ReleaseShare(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_Agent_SharePrivate_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Agent_SharePrivate_0(ctx context.Context, marshaler runtime.Marshaler, client AgentClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SharePrivateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_SharePrivate_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.SharePrivate(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Agent_SharePrivate_0(ctx context.Context, marshaler runtime.Marshaler, server AgentServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SharePrivateRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_SharePrivate_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.SharePrivate(ctx, &protoReq)
return msg, metadata, err
}
var (
filter_Agent_SharePublic_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Agent_SharePublic_0(ctx context.Context, marshaler runtime.Marshaler, client AgentClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SharePublicRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_SharePublic_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.SharePublic(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Agent_SharePublic_0(ctx context.Context, marshaler runtime.Marshaler, server AgentServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq SharePublicRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Agent_SharePublic_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.SharePublic(ctx, &protoReq)
return msg, metadata, err
}
func request_Agent_Status_0(ctx context.Context, marshaler runtime.Marshaler, client AgentClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq StatusRequest
var metadata runtime.ServerMetadata
msg, err := client.Status(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Agent_Status_0(ctx context.Context, marshaler runtime.Marshaler, server AgentServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq StatusRequest
var metadata runtime.ServerMetadata
msg, err := server.Status(ctx, &protoReq)
return msg, metadata, err
}
func request_Agent_Version_0(ctx context.Context, marshaler runtime.Marshaler, client AgentClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq VersionRequest
var metadata runtime.ServerMetadata
msg, err := client.Version(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Agent_Version_0(ctx context.Context, marshaler runtime.Marshaler, server AgentServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq VersionRequest
var metadata runtime.ServerMetadata
msg, err := server.Version(ctx, &protoReq)
return msg, metadata, err
}
// RegisterAgentHandlerServer registers the http handlers for service Agent to "mux".
// UnaryRPC :call AgentServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterAgentHandlerFromEndpoint instead.
func RegisterAgentHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AgentServer) error {
mux.Handle("POST", pattern_Agent_AccessPrivate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.Agent/AccessPrivate", runtime.WithHTTPPathPattern("/v1/agent/accessPrivate"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Agent_AccessPrivate_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_AccessPrivate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Agent_ReleaseAccess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.Agent/ReleaseAccess", runtime.WithHTTPPathPattern("/v1/agent/releaseAccess"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Agent_ReleaseAccess_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_ReleaseAccess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Agent_ReleaseShare_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.Agent/ReleaseShare", runtime.WithHTTPPathPattern("/v1/agent/releaseShare"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Agent_ReleaseShare_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_ReleaseShare_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Agent_SharePrivate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.Agent/SharePrivate", runtime.WithHTTPPathPattern("/v1/agent/sharePrivate"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Agent_SharePrivate_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_SharePrivate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Agent_SharePublic_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.Agent/SharePublic", runtime.WithHTTPPathPattern("/v1/agent/sharePublic"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Agent_SharePublic_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_SharePublic_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Agent_Status_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.Agent/Status", runtime.WithHTTPPathPattern("/v1/agent/status"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Agent_Status_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_Status_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Agent_Version_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/.Agent/Version", runtime.WithHTTPPathPattern("/v1/agent/version"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Agent_Version_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_Version_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterAgentHandlerFromEndpoint is same as RegisterAgentHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterAgentHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.DialContext(ctx, endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterAgentHandler(ctx, mux, conn)
}
// RegisterAgentHandler registers the http handlers for service Agent to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterAgentHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterAgentHandlerClient(ctx, mux, NewAgentClient(conn))
}
// RegisterAgentHandlerClient registers the http handlers for service Agent
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AgentClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AgentClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "AgentClient" to call the correct interceptors.
func RegisterAgentHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AgentClient) error {
mux.Handle("POST", pattern_Agent_AccessPrivate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.Agent/AccessPrivate", runtime.WithHTTPPathPattern("/v1/agent/accessPrivate"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Agent_AccessPrivate_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_AccessPrivate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Agent_ReleaseAccess_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.Agent/ReleaseAccess", runtime.WithHTTPPathPattern("/v1/agent/releaseAccess"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Agent_ReleaseAccess_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_ReleaseAccess_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Agent_ReleaseShare_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.Agent/ReleaseShare", runtime.WithHTTPPathPattern("/v1/agent/releaseShare"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Agent_ReleaseShare_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_ReleaseShare_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Agent_SharePrivate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.Agent/SharePrivate", runtime.WithHTTPPathPattern("/v1/agent/sharePrivate"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Agent_SharePrivate_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_SharePrivate_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Agent_SharePublic_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.Agent/SharePublic", runtime.WithHTTPPathPattern("/v1/agent/sharePublic"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Agent_SharePublic_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_SharePublic_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Agent_Status_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.Agent/Status", runtime.WithHTTPPathPattern("/v1/agent/status"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Agent_Status_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_Status_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Agent_Version_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/.Agent/Version", runtime.WithHTTPPathPattern("/v1/agent/version"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Agent_Version_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Agent_Version_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Agent_AccessPrivate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "agent", "accessPrivate"}, ""))
pattern_Agent_ReleaseAccess_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "agent", "releaseAccess"}, ""))
pattern_Agent_ReleaseShare_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "agent", "releaseShare"}, ""))
pattern_Agent_SharePrivate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "agent", "sharePrivate"}, ""))
pattern_Agent_SharePublic_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "agent", "sharePublic"}, ""))
pattern_Agent_Status_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "agent", "status"}, ""))
pattern_Agent_Version_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "agent", "version"}, ""))
)
var (
forward_Agent_AccessPrivate_0 = runtime.ForwardResponseMessage
forward_Agent_ReleaseAccess_0 = runtime.ForwardResponseMessage
forward_Agent_ReleaseShare_0 = runtime.ForwardResponseMessage
forward_Agent_SharePrivate_0 = runtime.ForwardResponseMessage
forward_Agent_SharePublic_0 = runtime.ForwardResponseMessage
forward_Agent_Status_0 = runtime.ForwardResponseMessage
forward_Agent_Version_0 = runtime.ForwardResponseMessage
)

150
agent/agentGrpc/agent.proto Normal file
View File

@ -0,0 +1,150 @@
syntax = "proto3";
option go_package = "github.com/openziti/zrok/agent/agentGrpc";
import "google/api/annotations.proto";
service Agent {
rpc AccessPrivate(AccessPrivateRequest) returns (AccessPrivateResponse) {
option(google.api.http) = {
post: "/v1/agent/accessPrivate"
};
}
rpc ReleaseAccess(ReleaseAccessRequest) returns (ReleaseAccessResponse) {
option(google.api.http) = {
post: "/v1/agent/releaseAccess"
};
}
rpc ReleaseShare(ReleaseShareRequest) returns (ReleaseShareResponse) {
option(google.api.http) = {
post: "/v1/agent/releaseShare"
};
}
rpc ShareReserved(ShareReservedRequest) returns (ShareReservedResponse) {}
rpc SharePrivate(SharePrivateRequest) returns (SharePrivateResponse) {
option(google.api.http) = {
post: "/v1/agent/sharePrivate"
};
}
rpc SharePublic(SharePublicRequest) returns (SharePublicResponse) {
option(google.api.http) = {
post: "/v1/agent/sharePublic"
};
}
rpc Status(StatusRequest) returns (StatusResponse) {
option(google.api.http) = {
get: "/v1/agent/status"
};
}
rpc Version(VersionRequest) returns (VersionResponse) {
option(google.api.http) = {
get: "/v1/agent/version"
};
}
}
message AccessDetail {
string frontendToken = 1;
string token = 2;
string bindAddress = 3;
repeated string responseHeaders = 4;
}
message AccessPrivateResponse{
string frontendToken = 1;
}
message AccessPrivateRequest{
string token = 1;
string bindAddress = 2;
bool autoMode = 3;
string autoAddress = 4;
uint32 autoStartPort = 5;
uint32 autoEndPort = 6;
repeated string responseHeaders = 7;
}
message ReleaseAccessRequest {
string frontendToken = 1;
}
message ReleaseAccessResponse {
}
message ReleaseShareRequest {
string token = 1;
}
message ReleaseShareResponse {
}
message ShareDetail {
string token = 1;
string shareMode = 2;
string backendMode = 3;
bool reserved = 4;
repeated string frontendEndpoint = 5;
string backendEndpoint = 6;
bool closed = 7;
string status = 8;
}
message SharePrivateRequest {
string target = 1;
string backendMode = 2;
bool insecure = 3;
bool closed = 4;
repeated string accessGrants = 5;
}
message SharePrivateResponse {
string token = 1;
}
message SharePublicRequest {
string target = 1;
repeated string basicAuth = 2;
repeated string frontendSelection = 3;
string backendMode = 4;
bool insecure = 5;
string oauthProvider = 6;
repeated string oauthEmailAddressPatterns = 7;
string oauthCheckInterval = 8;
bool closed = 9;
repeated string accessGrants = 10;
}
message SharePublicResponse {
string token = 1;
repeated string frontendEndpoints = 2;
}
message ShareReservedRequest {
string token = 1;
string overrideEndpoint = 2;
bool insecure = 3;
}
message ShareReservedResponse {
string token = 1;
string backendMode = 2;
string shareMode = 3;
repeated string frontendEndpoints = 4;
string target = 5;
}
message StatusRequest {
}
message StatusResponse {
repeated AccessDetail accesses = 1;
repeated ShareDetail shares = 2;
}
message VersionRequest {
}
message VersionResponse {
string v = 1;
string consoleEndpoint = 2;
}

View File

@ -0,0 +1,525 @@
{
"swagger": "2.0",
"info": {
"title": "agent/agentGrpc/agent.proto",
"version": "version not set"
},
"tags": [
{
"name": "Agent"
}
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/v1/agent/accessPrivate": {
"post": {
"operationId": "Agent_AccessPrivate",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/AccessPrivateResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "token",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "bindAddress",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "autoMode",
"in": "query",
"required": false,
"type": "boolean"
},
{
"name": "autoAddress",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "autoStartPort",
"in": "query",
"required": false,
"type": "integer",
"format": "int64"
},
{
"name": "autoEndPort",
"in": "query",
"required": false,
"type": "integer",
"format": "int64"
},
{
"name": "responseHeaders",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"tags": [
"Agent"
]
}
},
"/v1/agent/releaseAccess": {
"post": {
"operationId": "Agent_ReleaseAccess",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ReleaseAccessResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "frontendToken",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
"Agent"
]
}
},
"/v1/agent/releaseShare": {
"post": {
"operationId": "Agent_ReleaseShare",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/ReleaseShareResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "token",
"in": "query",
"required": false,
"type": "string"
}
],
"tags": [
"Agent"
]
}
},
"/v1/agent/sharePrivate": {
"post": {
"operationId": "Agent_SharePrivate",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/SharePrivateResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "target",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "backendMode",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "insecure",
"in": "query",
"required": false,
"type": "boolean"
},
{
"name": "closed",
"in": "query",
"required": false,
"type": "boolean"
},
{
"name": "accessGrants",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"tags": [
"Agent"
]
}
},
"/v1/agent/sharePublic": {
"post": {
"operationId": "Agent_SharePublic",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/SharePublicResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"parameters": [
{
"name": "target",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "basicAuth",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
},
{
"name": "frontendSelection",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
},
{
"name": "backendMode",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "insecure",
"in": "query",
"required": false,
"type": "boolean"
},
{
"name": "oauthProvider",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "oauthEmailAddressPatterns",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
},
{
"name": "oauthCheckInterval",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "closed",
"in": "query",
"required": false,
"type": "boolean"
},
{
"name": "accessGrants",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
}
],
"tags": [
"Agent"
]
}
},
"/v1/agent/status": {
"get": {
"operationId": "Agent_Status",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/StatusResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"tags": [
"Agent"
]
}
},
"/v1/agent/version": {
"get": {
"operationId": "Agent_Version",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/VersionResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/rpcStatus"
}
}
},
"tags": [
"Agent"
]
}
}
},
"definitions": {
"AccessDetail": {
"type": "object",
"properties": {
"frontendToken": {
"type": "string"
},
"token": {
"type": "string"
},
"bindAddress": {
"type": "string"
},
"responseHeaders": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"AccessPrivateResponse": {
"type": "object",
"properties": {
"frontendToken": {
"type": "string"
}
}
},
"ReleaseAccessResponse": {
"type": "object"
},
"ReleaseShareResponse": {
"type": "object"
},
"ShareDetail": {
"type": "object",
"properties": {
"token": {
"type": "string"
},
"shareMode": {
"type": "string"
},
"backendMode": {
"type": "string"
},
"reserved": {
"type": "boolean"
},
"frontendEndpoint": {
"type": "array",
"items": {
"type": "string"
}
},
"backendEndpoint": {
"type": "string"
},
"closed": {
"type": "boolean"
},
"status": {
"type": "string"
}
}
},
"SharePrivateResponse": {
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
},
"SharePublicResponse": {
"type": "object",
"properties": {
"token": {
"type": "string"
},
"frontendEndpoints": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"ShareReservedResponse": {
"type": "object",
"properties": {
"token": {
"type": "string"
},
"backendMode": {
"type": "string"
},
"shareMode": {
"type": "string"
},
"frontendEndpoints": {
"type": "array",
"items": {
"type": "string"
}
},
"target": {
"type": "string"
}
}
},
"StatusResponse": {
"type": "object",
"properties": {
"accesses": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/AccessDetail"
}
},
"shares": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/ShareDetail"
}
}
}
},
"VersionResponse": {
"type": "object",
"properties": {
"v": {
"type": "string"
},
"consoleEndpoint": {
"type": "string"
}
}
},
"protobufAny": {
"type": "object",
"properties": {
"@type": {
"type": "string"
}
},
"additionalProperties": {}
},
"rpcStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
},
"details": {
"type": "array",
"items": {
"type": "object",
"$ref": "#/definitions/protobufAny"
}
}
}
}
}
}

View File

@ -0,0 +1,387 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v5.27.3
// source: agent/agentGrpc/agent.proto
package agentGrpc
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Agent_AccessPrivate_FullMethodName = "/Agent/AccessPrivate"
Agent_ReleaseAccess_FullMethodName = "/Agent/ReleaseAccess"
Agent_ReleaseShare_FullMethodName = "/Agent/ReleaseShare"
Agent_ShareReserved_FullMethodName = "/Agent/ShareReserved"
Agent_SharePrivate_FullMethodName = "/Agent/SharePrivate"
Agent_SharePublic_FullMethodName = "/Agent/SharePublic"
Agent_Status_FullMethodName = "/Agent/Status"
Agent_Version_FullMethodName = "/Agent/Version"
)
// AgentClient is the client API for Agent service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type AgentClient interface {
AccessPrivate(ctx context.Context, in *AccessPrivateRequest, opts ...grpc.CallOption) (*AccessPrivateResponse, error)
ReleaseAccess(ctx context.Context, in *ReleaseAccessRequest, opts ...grpc.CallOption) (*ReleaseAccessResponse, error)
ReleaseShare(ctx context.Context, in *ReleaseShareRequest, opts ...grpc.CallOption) (*ReleaseShareResponse, error)
ShareReserved(ctx context.Context, in *ShareReservedRequest, opts ...grpc.CallOption) (*ShareReservedResponse, error)
SharePrivate(ctx context.Context, in *SharePrivateRequest, opts ...grpc.CallOption) (*SharePrivateResponse, error)
SharePublic(ctx context.Context, in *SharePublicRequest, opts ...grpc.CallOption) (*SharePublicResponse, error)
Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error)
Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error)
}
type agentClient struct {
cc grpc.ClientConnInterface
}
func NewAgentClient(cc grpc.ClientConnInterface) AgentClient {
return &agentClient{cc}
}
func (c *agentClient) AccessPrivate(ctx context.Context, in *AccessPrivateRequest, opts ...grpc.CallOption) (*AccessPrivateResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(AccessPrivateResponse)
err := c.cc.Invoke(ctx, Agent_AccessPrivate_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentClient) ReleaseAccess(ctx context.Context, in *ReleaseAccessRequest, opts ...grpc.CallOption) (*ReleaseAccessResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ReleaseAccessResponse)
err := c.cc.Invoke(ctx, Agent_ReleaseAccess_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentClient) ReleaseShare(ctx context.Context, in *ReleaseShareRequest, opts ...grpc.CallOption) (*ReleaseShareResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ReleaseShareResponse)
err := c.cc.Invoke(ctx, Agent_ReleaseShare_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentClient) ShareReserved(ctx context.Context, in *ShareReservedRequest, opts ...grpc.CallOption) (*ShareReservedResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ShareReservedResponse)
err := c.cc.Invoke(ctx, Agent_ShareReserved_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentClient) SharePrivate(ctx context.Context, in *SharePrivateRequest, opts ...grpc.CallOption) (*SharePrivateResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SharePrivateResponse)
err := c.cc.Invoke(ctx, Agent_SharePrivate_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentClient) SharePublic(ctx context.Context, in *SharePublicRequest, opts ...grpc.CallOption) (*SharePublicResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SharePublicResponse)
err := c.cc.Invoke(ctx, Agent_SharePublic_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentClient) Status(ctx context.Context, in *StatusRequest, opts ...grpc.CallOption) (*StatusResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(StatusResponse)
err := c.cc.Invoke(ctx, Agent_Status_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *agentClient) Version(ctx context.Context, in *VersionRequest, opts ...grpc.CallOption) (*VersionResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(VersionResponse)
err := c.cc.Invoke(ctx, Agent_Version_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// AgentServer is the server API for Agent service.
// All implementations must embed UnimplementedAgentServer
// for forward compatibility.
type AgentServer interface {
AccessPrivate(context.Context, *AccessPrivateRequest) (*AccessPrivateResponse, error)
ReleaseAccess(context.Context, *ReleaseAccessRequest) (*ReleaseAccessResponse, error)
ReleaseShare(context.Context, *ReleaseShareRequest) (*ReleaseShareResponse, error)
ShareReserved(context.Context, *ShareReservedRequest) (*ShareReservedResponse, error)
SharePrivate(context.Context, *SharePrivateRequest) (*SharePrivateResponse, error)
SharePublic(context.Context, *SharePublicRequest) (*SharePublicResponse, error)
Status(context.Context, *StatusRequest) (*StatusResponse, error)
Version(context.Context, *VersionRequest) (*VersionResponse, error)
mustEmbedUnimplementedAgentServer()
}
// UnimplementedAgentServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedAgentServer struct{}
func (UnimplementedAgentServer) AccessPrivate(context.Context, *AccessPrivateRequest) (*AccessPrivateResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method AccessPrivate not implemented")
}
func (UnimplementedAgentServer) ReleaseAccess(context.Context, *ReleaseAccessRequest) (*ReleaseAccessResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ReleaseAccess not implemented")
}
func (UnimplementedAgentServer) ReleaseShare(context.Context, *ReleaseShareRequest) (*ReleaseShareResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ReleaseShare not implemented")
}
func (UnimplementedAgentServer) ShareReserved(context.Context, *ShareReservedRequest) (*ShareReservedResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ShareReserved not implemented")
}
func (UnimplementedAgentServer) SharePrivate(context.Context, *SharePrivateRequest) (*SharePrivateResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SharePrivate not implemented")
}
func (UnimplementedAgentServer) SharePublic(context.Context, *SharePublicRequest) (*SharePublicResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method SharePublic not implemented")
}
func (UnimplementedAgentServer) Status(context.Context, *StatusRequest) (*StatusResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Status not implemented")
}
func (UnimplementedAgentServer) Version(context.Context, *VersionRequest) (*VersionResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Version not implemented")
}
func (UnimplementedAgentServer) mustEmbedUnimplementedAgentServer() {}
func (UnimplementedAgentServer) testEmbeddedByValue() {}
// UnsafeAgentServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to AgentServer will
// result in compilation errors.
type UnsafeAgentServer interface {
mustEmbedUnimplementedAgentServer()
}
func RegisterAgentServer(s grpc.ServiceRegistrar, srv AgentServer) {
// If the following call pancis, it indicates UnimplementedAgentServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Agent_ServiceDesc, srv)
}
func _Agent_AccessPrivate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AccessPrivateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServer).AccessPrivate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Agent_AccessPrivate_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServer).AccessPrivate(ctx, req.(*AccessPrivateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Agent_ReleaseAccess_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReleaseAccessRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServer).ReleaseAccess(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Agent_ReleaseAccess_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServer).ReleaseAccess(ctx, req.(*ReleaseAccessRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Agent_ReleaseShare_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ReleaseShareRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServer).ReleaseShare(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Agent_ReleaseShare_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServer).ReleaseShare(ctx, req.(*ReleaseShareRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Agent_ShareReserved_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ShareReservedRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServer).ShareReserved(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Agent_ShareReserved_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServer).ShareReserved(ctx, req.(*ShareReservedRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Agent_SharePrivate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SharePrivateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServer).SharePrivate(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Agent_SharePrivate_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServer).SharePrivate(ctx, req.(*SharePrivateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Agent_SharePublic_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SharePublicRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServer).SharePublic(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Agent_SharePublic_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServer).SharePublic(ctx, req.(*SharePublicRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Agent_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(StatusRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServer).Status(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Agent_Status_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServer).Status(ctx, req.(*StatusRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Agent_Version_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(VersionRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AgentServer).Version(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Agent_Version_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AgentServer).Version(ctx, req.(*VersionRequest))
}
return interceptor(ctx, in, info, handler)
}
// Agent_ServiceDesc is the grpc.ServiceDesc for Agent service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Agent_ServiceDesc = grpc.ServiceDesc{
ServiceName: "Agent",
HandlerType: (*AgentServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "AccessPrivate",
Handler: _Agent_AccessPrivate_Handler,
},
{
MethodName: "ReleaseAccess",
Handler: _Agent_ReleaseAccess_Handler,
},
{
MethodName: "ReleaseShare",
Handler: _Agent_ReleaseShare_Handler,
},
{
MethodName: "ShareReserved",
Handler: _Agent_ShareReserved_Handler,
},
{
MethodName: "SharePrivate",
Handler: _Agent_SharePrivate_Handler,
},
{
MethodName: "SharePublic",
Handler: _Agent_SharePublic_Handler,
},
{
MethodName: "Status",
Handler: _Agent_Status_Handler,
},
{
MethodName: "Version",
Handler: _Agent_Version_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "agent/agentGrpc/agent.proto",
}

10
agent/agentGrpc/tools.go Normal file
View File

@ -0,0 +1,10 @@
//go:build tools
package agentGrpc
import (
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway"
_ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2"
_ "google.golang.org/grpc/cmd/protoc-gen-go-grpc"
_ "google.golang.org/protobuf/cmd/protoc-gen-go"
)

24
agent/agentUi/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

50
agent/agentUi/README.md Normal file
View File

@ -0,0 +1,50 @@
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
- Configure the top-level `parserOptions` property like this:
```js
export default tseslint.config({
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
```
- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
- Optionally add `...tseslint.configs.stylisticTypeChecked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
```js
// eslint.config.js
import react from 'eslint-plugin-react'
export default tseslint.config({
// Set the react version
settings: { react: { version: '18.3' } },
plugins: {
// Add the react plugin
react,
},
rules: {
// other rules...
// Enable its recommended rules
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
},
})
```

6
agent/agentUi/embed.go Normal file
View File

@ -0,0 +1,6 @@
package agentUi
import "embed"
//go:embed dist
var FS embed.FS

View File

@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)

17
agent/agentUi/index.html Normal file
View File

@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/zrok.png" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>zrok Agent Console</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@ -0,0 +1,53 @@
package agentUi
import (
"github.com/sirupsen/logrus"
"io/fs"
"net/http"
"os"
"path/filepath"
"strings"
)
const staticPath = "dist"
func Middleware(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/v1") {
handler.ServeHTTP(w, r)
return
}
path := filepath.ToSlash(filepath.Join(staticPath, r.URL.Path))
logrus.Debugf("path = %v", path)
f, err := FS.Open(path)
if os.IsNotExist(err) {
// file does not exist, serve index.gohtml
index, err := FS.ReadFile(filepath.ToSlash(filepath.Join(staticPath, "index.html")))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusAccepted)
_, _ = w.Write(index)
return
} else if err != nil {
// if we got an error (that wasn't that the file doesn't exist) stating the
// file, return a 500 internal server error and stop
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer func() { _ = f.Close() }()
// get the subdirectory of the static dir
if statics, err := fs.Sub(FS, staticPath); err == nil {
// otherwise, use http.FileServer to serve the static dir
http.FileServer(http.FS(statics)).ServeHTTP(w, r)
} else {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}

3931
agent/agentUi/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
{
"name": "agentui",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/icons-material": "^6.1.7",
"@mui/material": "^6.1.7",
"formik": "^2.4.6",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"globals": "^15.11.0",
"typescript-eslint": "^8.15.0",
"vite": "^5.4.10"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,53 @@
import {AgentObject} from "./model/overview.ts";
import {AppBar, Box, Button, Card, Chip, Grid2, Toolbar, Typography} from "@mui/material";
import LanIcon from "@mui/icons-material/Lan";
import {AccessDetail} from "./api";
import DeleteIcon from "@mui/icons-material/Delete";
import {GetAgentApi} from "./model/api.ts";
interface AccessCardProps {
accessObject: AgentObject;
}
const AccessCard = ({ accessObject }: AccessCardProps) => {
let access = (accessObject.v as AccessDetail);
const releaseAccess = () => {
GetAgentApi().agentReleaseAccess({frontendToken: access.frontendToken})
.catch(e => {
console.log("error releasing access", e);
});
}
return (
<Card>
<AppBar position="sticky">
<Toolbar variant="dense">
<LanIcon />
<Grid2 container sx={{ flexGrow: 1 }}>
<Grid2 display="flex" justifyContent="center" size="grow">
<Typography variant="h6" component="div" style={{ color: "#9bf316" }}>{access.frontendToken}</Typography>
</Grid2>
</Grid2>
<Grid2 container>
<Grid2 display="flex" justifyContent="right">
<Chip label="private" size="small" style={{ backgroundColor: "#9bf316" }} />
</Grid2>
</Grid2>
</Toolbar>
</AppBar>
<Box sx={{ p: 2, textAlign: "center" }}>
<Typography variant="h6" component="div">
{access.token} &rarr; {access.bindAddress}
</Typography>
</Box>
<Grid2 container sx={{ flexGrow: 1 }}>
<Grid2 display="flex" justifyContent="right" size="grow">
<Button variant="contained" onClick={releaseAccess}><DeleteIcon /></Button>
</Grid2>
</Grid2>
</Card>
);
}
export default AccessCard;

View File

@ -0,0 +1,69 @@
import {useEffect, useState} from "react";
import {GetAgentApi} from "./model/api.ts";
import NavBar from "./NavBar.tsx";
import {AgentObject, buildOverview} from "./model/overview.ts";
import Overview from "./Overview.tsx";
import NewShareModal from "./NewShareModal.tsx";
import NewAccessModal from "./NewAccessModal.tsx";
const AgentUi = () => {
const [version, setVersion] = useState("unset");
const [overview, setOverview] = useState(new Array<AgentObject>());
const [newShareOpen, setNewShareOpen] = useState(false);
const [newAccessOpen, setNewAccessOpen] = useState(false);
const openNewShare = () => {
setNewShareOpen(true);
}
const closeNewShare = () => {
setNewShareOpen(false);
}
const openNewAccess = () => {
setNewAccessOpen(true);
}
const closeNewAccess = () => {
setNewAccessOpen(false);
}
useEffect(() => {
GetAgentApi().agentVersion()
.then(r => {
if(r.v) {
setVersion(r.v);
} else {
console.log("unexpected", r);
}
})
.catch(e => {
console.log(e);
});
}, []);
useEffect(() => {
let interval = setInterval(() => {
GetAgentApi().agentStatus()
.then(r => {
setOverview(buildOverview(r));
})
.catch(e => {
console.log(e);
})
}, 1000);
return () => {
clearInterval(interval);
setOverview(new Array<AgentObject>());
}
}, []);
return (
<>
<NavBar shareClick={openNewShare} accessClick={openNewAccess} />
<Overview overview={overview} shareClick={openNewShare} accessClick={openNewAccess} />
<NewShareModal isOpen={newShareOpen} close={closeNewShare} />
<NewAccessModal isOpen={newAccessOpen} close={closeNewAccess} />
</>
);
}
export default AgentUi;

View File

@ -0,0 +1,40 @@
import {AppBar, Box, Button, Grid2, Toolbar, Typography} from "@mui/material";
import LanIcon from "@mui/icons-material/Lan";
import ShareIcon from "@mui/icons-material/Share";
import zrokLogo from "./assets/zrok-1.0.0-rocket-green.svg";
interface NavBarProps {
shareClick: () => void;
accessClick: () => void;
}
const NavBar = ({ shareClick, accessClick }: NavBarProps) => {
return (
<Box ssx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<Typography variant="h6" sx={{ flexGrow: 1 }}>
<Grid2 container sx={{ flexGrow: 1 }}>
<Grid2 display="flex" justifyContent="left">
<img src={zrokLogo} height="30" />
</Grid2>
<Grid2 display="flex" justifyContent="left" size="grow" sx={{ ml: 3 }} color="#9bf316">
<strong>z r o k &nbsp; Agent</strong>
</Grid2>
</Grid2>
</Typography>
<Grid2 container sx={{ flexGrow: 1 }}>
<Grid2 display="flex" justifyContent="right" size="grow">
<Button color="inherit" onClick={shareClick}><ShareIcon /></Button>
</Grid2>
<Grid2 display="flex" justifyContent="right">
<Button color="inherit" onClick={accessClick}><LanIcon /></Button>
</Grid2>
</Grid2>
</Toolbar>
</AppBar>
</Box>
);
}
export default NavBar

View File

@ -0,0 +1,69 @@
import {useState} from "react";
import {useFormik} from "formik";
import {GetAgentApi} from "./model/api.ts";
import {Box, Button, Modal, TextField, Typography} from "@mui/material";
import {modalStyle} from "./model/theme.ts";
import * as React from "react";
interface NewAccessModalProps {
close: () => void;
isOpen: boolean;
}
const NewAccessModal = ({ close, isOpen }: NewAccessModalProps) => {
const [errorMessage, setErrorMessage] = useState(null as React.JSX.Element);
const newAccessForm = useFormik({
initialValues: {
token: "",
bindAddress: "",
},
onSubmit: v => {
setErrorMessage(null as React.JSX.Element);
GetAgentApi().agentAccessPrivate(v)
.then(r => {
close();
})
.catch(e => {
e.response.json().then(ex => {
setErrorMessage(<span>{ex.message}</span>);
console.log(ex.message);
})
});
}
});
return (
<Modal open={isOpen} onClose={close}>
<Box sx={{...modalStyle}}>
<Typography><h2>Access...</h2></Typography>
<Typography color="red"><h3>{errorMessage}</h3></Typography>
<form onSubmit={newAccessForm.handleSubmit}>
<TextField
fullWidth
id="token"
name="token"
label="Share Token"
value={newAccessForm.values.token}
onChange={newAccessForm.handleChange}
onBlur={newAccessForm.handleBlur}
sx={{mt: 2}}
/>
<TextField
fullWidth
id="bindAddress"
name="bindAddress"
label="Bind Address"
value={newAccessForm.values.bindAddress}
onChange={newAccessForm.handleChange}
onBlur={newAccessForm.handleBlur}
sx={{mt: 2}}
/>
<Button color="primary" variant="contained" type="submit" sx={{mt: 2}}>Create Access</Button>
</form>
</Box>
</Modal>
);
}
export default NewAccessModal;

View File

@ -0,0 +1,146 @@
import {useFormik} from "formik";
import {GetAgentApi} from "./model/api.ts";
import {useState} from "react";
import {Box, Button, Checkbox, FormControlLabel, MenuItem, Modal, TextField, Typography} from "@mui/material";
import {modalStyle} from "./model/theme.ts";
import * as React from "react";
interface NewShareModalProps {
close: () => void;
isOpen: boolean;
}
const NewShareModal = ({ close, isOpen }: NewShareModalProps) => {
const [errorMessage, setErrorMessage] = useState(null as React.JSX.Element);
const form = useFormik({
initialValues: {
shareMode: "public",
backendMode: "proxy",
target: "",
insecure: false,
},
onSubmit: v => {
setErrorMessage(null as React.JSX.Element);
switch(v.shareMode) {
case "public":
GetAgentApi().agentSharePublic(v)
.then(r => {
close();
})
.catch(e => {
e.response.json().then(ex => {
setErrorMessage(<span>{ex.message}</span>);
console.log(ex.message);
})
});
break;
case "private":
GetAgentApi().agentSharePrivate(v)
.then(r => {
close();
})
.catch(e => {
e.response().json().then(ex => {
setErrorMessage(<span>{ex.message}</span>);
console.log(ex.message);
})
});
break;
}
},
});
return (
<Modal open={isOpen} onClose={close}>
<Box sx={{ ...modalStyle }}>
<Typography><h2>Share...</h2></Typography>
<Typography color="red"><h3>{errorMessage}</h3></Typography>
<form onSubmit={form.handleSubmit}>
<TextField
fullWidth
select
id="shareMode"
name="shareMode"
label="Share Mode"
value={form.values.shareMode}
onChange={form.handleChange}
onBlur={form.handleBlur}
sx={{ mt: 2 }}
>
<MenuItem value="public">public</MenuItem>
<MenuItem value="private">private</MenuItem>
</TextField>
{form.values.shareMode === "public" && (
<TextField
fullWidth select
id="backendMode"
name="backendMode"
label="Backend Mode"
value={form.values.backendMode}
onChange={form.handleChange}
onBlur={form.handleBlur}
sx={{ mt: 2 }}
>
<MenuItem value="proxy">proxy</MenuItem>
<MenuItem value="web">web</MenuItem>
<MenuItem value="caddy">caddy</MenuItem>
<MenuItem value="drive">drive</MenuItem>
</TextField>
)}
{form.values.shareMode === "private" && (
<TextField
fullWidth select
id="backendMode"
name="backendMode"
label="Backend Mode"
value={form.values.backendMode}
onChange={form.handleChange}
onBlur={form.handleBlur}
sx={{ mt: 2 }}
>
<MenuItem value="proxy">proxy</MenuItem>
<MenuItem value="web">web</MenuItem>
<MenuItem value="tcpTunnel">tcpTunnel</MenuItem>
<MenuItem value="udpTunnel">udpTunnel</MenuItem>
<MenuItem value="caddy">caddy</MenuItem>
<MenuItem value="drive">drive</MenuItem>
<MenuItem value="socks">socks</MenuItem>
<MenuItem value="vpn">vpn</MenuItem>
</TextField>
)}
<TextField
fullWidth
id="target"
name="target"
label="Target"
value={form.values.target}
onChange={form.handleChange}
onBlur={form.handleBlur}
sx={{ mt: 2 }}
/>
{form.values.backendMode === "proxy" && (
<Box>
<FormControlLabel
control={<Checkbox
id="insecure"
name="insecure"
label="Insecure"
checked={form.values.insecure}
onChange={form.handleChange}
onBlur={form.handleBlur}
/>}
label="Insecure"
sx={{ mt: 2 }}
/>
</Box>
)}
<Button color="primary" variant="contained" type="submit" sx={{ mt: 2 }}>Create Share</Button>
</form>
</Box>
</Modal>
);
}
export default NewShareModal;

View File

@ -0,0 +1,47 @@
import {AgentObject} from "./model/overview.ts";
import {Box, Card, Grid2, Typography} from "@mui/material";
import ShareIcon from "@mui/icons-material/Share";
import LanIcon from "@mui/icons-material/Lan";
import ShareCard from "./ShareCard.tsx";
import AccessCard from "./AccessCard.tsx";
interface OverviewProps {
overview: Array<AgentObject>;
shareClick: () => void;
accessClick: () => void;
}
const Overview = ({ overview, shareClick, accessClick }: OverviewProps) => {
let cards = [];
if(overview.length > 0) {
overview.forEach(row => {
switch(row.type) {
case "access":
cards.push(<Grid2 size={{ xs: 12, md: 6 }}><AccessCard accessObject={row} /></Grid2>);
break;
case "share":
cards.push(<Grid2 size={{ xs: 12, md: 6 }}><ShareCard shareObject={row} /></Grid2>);
break;
}
});
} else {
cards.push(<Grid2 size={{ xs: 12 }}>
<Card key="empty">
<Box sx={{ p: 2, textAlign: "center" }}>
<Typography variant="h6" component="div">
zrok Agent is empty! Add a <a href={"#"} onClick={shareClick}>share <ShareIcon/></a> or <a
href={"#"} onClick={accessClick}>access <LanIcon/></a> share to get started.
</Typography>
</Box>
</Card>
</Grid2>);
}
return (
<Grid2 container spacing={2}>
{cards}
</Grid2>
);
}
export default Overview;

View File

@ -0,0 +1,59 @@
import * as React from "react";
import {AgentObject} from "./model/overview.ts";
import {ShareDetail} from "./api";
import {AppBar, Box, Button, Card, Chip, Grid2, Toolbar, Typography} from "@mui/material";
import ShareIcon from "@mui/icons-material/Share";
import DeleteIcon from "@mui/icons-material/Delete";
import {GetAgentApi} from "./model/api.ts";
interface ShareCardProps {
shareObject: AgentObject;
}
const ShareCard = ({ shareObject }: ShareCardProps) => {
let frontends = new Array<React.JSX.Element>();
let share = (shareObject.v as ShareDetail);
share.frontendEndpoint!.map(fe => {
frontends.push(<a key={share.token} href={fe} target="_">{fe}</a>);
});
const releaseShare = () => {
GetAgentApi().agentReleaseShare({token: share.token})
.catch(e => {
console.log(e);
});
}
return (
<Card>
<AppBar position="sticky">
<Toolbar variant="dense">
<ShareIcon />
<Grid2 container sx={{ flexGrow: 1 }}>
<Grid2 display="flex" justifyContent="center" size="grow">
<Typography variant="h6" component="div" style={{ color: "#9bf316" }}>{share.token}</Typography>
</Grid2>
</Grid2>
<Grid2 container>
<Grid2 display="flex" justifyContent="right">
<Chip label={share.shareMode} size="small" style={{ backgroundColor: "#9bf316" }} sx={{ mr: 1}} />
<Chip label={share.backendMode} size="small" style={{ backgroundColor: "#9bf316" }} />
</Grid2>
</Grid2>
</Toolbar>
</AppBar>
<Box sx={{ p: 2, textAlign: "center" }}>
<Typography variant="h6" component="div">
{share.backendEndpoint} &rarr; {frontends} <br/>
</Typography>
</Box>
<Grid2 container sx={{ flexGrow: 1 }}>
<Grid2 display="flex" justifyContent="right" size="grow">
<Button variant="contained" onClick={releaseShare}><DeleteIcon /></Button>
</Grid2>
</Grid2>
</Card>
);
}
export default ShareCard;

View File

@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -0,0 +1,16 @@
.openapi-generator-ignore
apis/AgentApi.ts
apis/index.ts
index.ts
models/AccessDetail.ts
models/AccessPrivateResponse.ts
models/ProtobufAny.ts
models/RpcStatus.ts
models/ShareDetail.ts
models/SharePrivateResponse.ts
models/SharePublicResponse.ts
models/ShareReservedResponse.ts
models/StatusResponse.ts
models/VersionResponse.ts
models/index.ts
runtime.ts

View File

@ -0,0 +1 @@
7.7.0

View File

@ -0,0 +1,348 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import * as runtime from '../runtime';
import type {
AccessPrivateResponse,
RpcStatus,
SharePrivateResponse,
SharePublicResponse,
StatusResponse,
VersionResponse,
} from '../models/index';
import {
AccessPrivateResponseFromJSON,
AccessPrivateResponseToJSON,
RpcStatusFromJSON,
RpcStatusToJSON,
SharePrivateResponseFromJSON,
SharePrivateResponseToJSON,
SharePublicResponseFromJSON,
SharePublicResponseToJSON,
StatusResponseFromJSON,
StatusResponseToJSON,
VersionResponseFromJSON,
VersionResponseToJSON,
} from '../models/index';
export interface AgentAccessPrivateRequest {
token?: string;
bindAddress?: string;
autoMode?: boolean;
autoAddress?: string;
autoStartPort?: number;
autoEndPort?: number;
responseHeaders?: Array<string>;
}
export interface AgentReleaseAccessRequest {
frontendToken?: string;
}
export interface AgentReleaseShareRequest {
token?: string;
}
export interface AgentSharePrivateRequest {
target?: string;
backendMode?: string;
insecure?: boolean;
closed?: boolean;
accessGrants?: Array<string>;
}
export interface AgentSharePublicRequest {
target?: string;
basicAuth?: Array<string>;
frontendSelection?: Array<string>;
backendMode?: string;
insecure?: boolean;
oauthProvider?: string;
oauthEmailAddressPatterns?: Array<string>;
oauthCheckInterval?: string;
closed?: boolean;
accessGrants?: Array<string>;
}
/**
*
*/
export class AgentApi extends runtime.BaseAPI {
/**
*/
async agentAccessPrivateRaw(requestParameters: AgentAccessPrivateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<AccessPrivateResponse>> {
const queryParameters: any = {};
if (requestParameters['token'] != null) {
queryParameters['token'] = requestParameters['token'];
}
if (requestParameters['bindAddress'] != null) {
queryParameters['bindAddress'] = requestParameters['bindAddress'];
}
if (requestParameters['autoMode'] != null) {
queryParameters['autoMode'] = requestParameters['autoMode'];
}
if (requestParameters['autoAddress'] != null) {
queryParameters['autoAddress'] = requestParameters['autoAddress'];
}
if (requestParameters['autoStartPort'] != null) {
queryParameters['autoStartPort'] = requestParameters['autoStartPort'];
}
if (requestParameters['autoEndPort'] != null) {
queryParameters['autoEndPort'] = requestParameters['autoEndPort'];
}
if (requestParameters['responseHeaders'] != null) {
queryParameters['responseHeaders'] = requestParameters['responseHeaders'];
}
const headerParameters: runtime.HTTPHeaders = {};
const response = await this.request({
path: `/v1/agent/accessPrivate`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => AccessPrivateResponseFromJSON(jsonValue));
}
/**
*/
async agentAccessPrivate(requestParameters: AgentAccessPrivateRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<AccessPrivateResponse> {
const response = await this.agentAccessPrivateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
*/
async agentReleaseAccessRaw(requestParameters: AgentReleaseAccessRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<object>> {
const queryParameters: any = {};
if (requestParameters['frontendToken'] != null) {
queryParameters['frontendToken'] = requestParameters['frontendToken'];
}
const headerParameters: runtime.HTTPHeaders = {};
const response = await this.request({
path: `/v1/agent/releaseAccess`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse<any>(response);
}
/**
*/
async agentReleaseAccess(requestParameters: AgentReleaseAccessRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<object> {
const response = await this.agentReleaseAccessRaw(requestParameters, initOverrides);
return await response.value();
}
/**
*/
async agentReleaseShareRaw(requestParameters: AgentReleaseShareRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<object>> {
const queryParameters: any = {};
if (requestParameters['token'] != null) {
queryParameters['token'] = requestParameters['token'];
}
const headerParameters: runtime.HTTPHeaders = {};
const response = await this.request({
path: `/v1/agent/releaseShare`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse<any>(response);
}
/**
*/
async agentReleaseShare(requestParameters: AgentReleaseShareRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<object> {
const response = await this.agentReleaseShareRaw(requestParameters, initOverrides);
return await response.value();
}
/**
*/
async agentSharePrivateRaw(requestParameters: AgentSharePrivateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<SharePrivateResponse>> {
const queryParameters: any = {};
if (requestParameters['target'] != null) {
queryParameters['target'] = requestParameters['target'];
}
if (requestParameters['backendMode'] != null) {
queryParameters['backendMode'] = requestParameters['backendMode'];
}
if (requestParameters['insecure'] != null) {
queryParameters['insecure'] = requestParameters['insecure'];
}
if (requestParameters['closed'] != null) {
queryParameters['closed'] = requestParameters['closed'];
}
if (requestParameters['accessGrants'] != null) {
queryParameters['accessGrants'] = requestParameters['accessGrants'];
}
const headerParameters: runtime.HTTPHeaders = {};
const response = await this.request({
path: `/v1/agent/sharePrivate`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => SharePrivateResponseFromJSON(jsonValue));
}
/**
*/
async agentSharePrivate(requestParameters: AgentSharePrivateRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<SharePrivateResponse> {
const response = await this.agentSharePrivateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
*/
async agentSharePublicRaw(requestParameters: AgentSharePublicRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<SharePublicResponse>> {
const queryParameters: any = {};
if (requestParameters['target'] != null) {
queryParameters['target'] = requestParameters['target'];
}
if (requestParameters['basicAuth'] != null) {
queryParameters['basicAuth'] = requestParameters['basicAuth'];
}
if (requestParameters['frontendSelection'] != null) {
queryParameters['frontendSelection'] = requestParameters['frontendSelection'];
}
if (requestParameters['backendMode'] != null) {
queryParameters['backendMode'] = requestParameters['backendMode'];
}
if (requestParameters['insecure'] != null) {
queryParameters['insecure'] = requestParameters['insecure'];
}
if (requestParameters['oauthProvider'] != null) {
queryParameters['oauthProvider'] = requestParameters['oauthProvider'];
}
if (requestParameters['oauthEmailAddressPatterns'] != null) {
queryParameters['oauthEmailAddressPatterns'] = requestParameters['oauthEmailAddressPatterns'];
}
if (requestParameters['oauthCheckInterval'] != null) {
queryParameters['oauthCheckInterval'] = requestParameters['oauthCheckInterval'];
}
if (requestParameters['closed'] != null) {
queryParameters['closed'] = requestParameters['closed'];
}
if (requestParameters['accessGrants'] != null) {
queryParameters['accessGrants'] = requestParameters['accessGrants'];
}
const headerParameters: runtime.HTTPHeaders = {};
const response = await this.request({
path: `/v1/agent/sharePublic`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => SharePublicResponseFromJSON(jsonValue));
}
/**
*/
async agentSharePublic(requestParameters: AgentSharePublicRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<SharePublicResponse> {
const response = await this.agentSharePublicRaw(requestParameters, initOverrides);
return await response.value();
}
/**
*/
async agentStatusRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<StatusResponse>> {
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
const response = await this.request({
path: `/v1/agent/status`,
method: 'GET',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => StatusResponseFromJSON(jsonValue));
}
/**
*/
async agentStatus(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<StatusResponse> {
const response = await this.agentStatusRaw(initOverrides);
return await response.value();
}
/**
*/
async agentVersionRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<VersionResponse>> {
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
const response = await this.request({
path: `/v1/agent/version`,
method: 'GET',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => VersionResponseFromJSON(jsonValue));
}
/**
*/
async agentVersion(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<VersionResponse> {
const response = await this.agentVersionRaw(initOverrides);
return await response.value();
}
}

View File

@ -0,0 +1,3 @@
/* tslint:disable */
/* eslint-disable */
export * from './AgentApi';

View File

@ -0,0 +1,84 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface AccessDetail
*/
export interface AccessDetail {
/**
*
* @type {string}
* @memberof AccessDetail
*/
frontendToken?: string;
/**
*
* @type {string}
* @memberof AccessDetail
*/
token?: string;
/**
*
* @type {string}
* @memberof AccessDetail
*/
bindAddress?: string;
/**
*
* @type {Array<string>}
* @memberof AccessDetail
*/
responseHeaders?: Array<string>;
}
/**
* Check if a given object implements the AccessDetail interface.
*/
export function instanceOfAccessDetail(value: object): value is AccessDetail {
return true;
}
export function AccessDetailFromJSON(json: any): AccessDetail {
return AccessDetailFromJSONTyped(json, false);
}
export function AccessDetailFromJSONTyped(json: any, ignoreDiscriminator: boolean): AccessDetail {
if (json == null) {
return json;
}
return {
'frontendToken': json['frontendToken'] == null ? undefined : json['frontendToken'],
'token': json['token'] == null ? undefined : json['token'],
'bindAddress': json['bindAddress'] == null ? undefined : json['bindAddress'],
'responseHeaders': json['responseHeaders'] == null ? undefined : json['responseHeaders'],
};
}
export function AccessDetailToJSON(value?: AccessDetail | null): any {
if (value == null) {
return value;
}
return {
'frontendToken': value['frontendToken'],
'token': value['token'],
'bindAddress': value['bindAddress'],
'responseHeaders': value['responseHeaders'],
};
}

View File

@ -0,0 +1,60 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface AccessPrivateResponse
*/
export interface AccessPrivateResponse {
/**
*
* @type {string}
* @memberof AccessPrivateResponse
*/
frontendToken?: string;
}
/**
* Check if a given object implements the AccessPrivateResponse interface.
*/
export function instanceOfAccessPrivateResponse(value: object): value is AccessPrivateResponse {
return true;
}
export function AccessPrivateResponseFromJSON(json: any): AccessPrivateResponse {
return AccessPrivateResponseFromJSONTyped(json, false);
}
export function AccessPrivateResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): AccessPrivateResponse {
if (json == null) {
return json;
}
return {
'frontendToken': json['frontendToken'] == null ? undefined : json['frontendToken'],
};
}
export function AccessPrivateResponseToJSON(value?: AccessPrivateResponse | null): any {
if (value == null) {
return value;
}
return {
'frontendToken': value['frontendToken'],
};
}

View File

@ -0,0 +1,63 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface ProtobufAny
*/
export interface ProtobufAny {
[key: string]: object | any;
/**
*
* @type {string}
* @memberof ProtobufAny
*/
type?: string;
}
/**
* Check if a given object implements the ProtobufAny interface.
*/
export function instanceOfProtobufAny(value: object): value is ProtobufAny {
return true;
}
export function ProtobufAnyFromJSON(json: any): ProtobufAny {
return ProtobufAnyFromJSONTyped(json, false);
}
export function ProtobufAnyFromJSONTyped(json: any, ignoreDiscriminator: boolean): ProtobufAny {
if (json == null) {
return json;
}
return {
...json,
'type': json['@type'] == null ? undefined : json['@type'],
};
}
export function ProtobufAnyToJSON(value?: ProtobufAny | null): any {
if (value == null) {
return value;
}
return {
...value,
'@type': value['type'],
};
}

View File

@ -0,0 +1,83 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
import type { ProtobufAny } from './ProtobufAny';
import {
ProtobufAnyFromJSON,
ProtobufAnyFromJSONTyped,
ProtobufAnyToJSON,
} from './ProtobufAny';
/**
*
* @export
* @interface RpcStatus
*/
export interface RpcStatus {
/**
*
* @type {number}
* @memberof RpcStatus
*/
code?: number;
/**
*
* @type {string}
* @memberof RpcStatus
*/
message?: string;
/**
*
* @type {Array<ProtobufAny>}
* @memberof RpcStatus
*/
details?: Array<ProtobufAny>;
}
/**
* Check if a given object implements the RpcStatus interface.
*/
export function instanceOfRpcStatus(value: object): value is RpcStatus {
return true;
}
export function RpcStatusFromJSON(json: any): RpcStatus {
return RpcStatusFromJSONTyped(json, false);
}
export function RpcStatusFromJSONTyped(json: any, ignoreDiscriminator: boolean): RpcStatus {
if (json == null) {
return json;
}
return {
'code': json['code'] == null ? undefined : json['code'],
'message': json['message'] == null ? undefined : json['message'],
'details': json['details'] == null ? undefined : ((json['details'] as Array<any>).map(ProtobufAnyFromJSON)),
};
}
export function RpcStatusToJSON(value?: RpcStatus | null): any {
if (value == null) {
return value;
}
return {
'code': value['code'],
'message': value['message'],
'details': value['details'] == null ? undefined : ((value['details'] as Array<any>).map(ProtobufAnyToJSON)),
};
}

View File

@ -0,0 +1,116 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface ShareDetail
*/
export interface ShareDetail {
/**
*
* @type {string}
* @memberof ShareDetail
*/
token?: string;
/**
*
* @type {string}
* @memberof ShareDetail
*/
shareMode?: string;
/**
*
* @type {string}
* @memberof ShareDetail
*/
backendMode?: string;
/**
*
* @type {boolean}
* @memberof ShareDetail
*/
reserved?: boolean;
/**
*
* @type {Array<string>}
* @memberof ShareDetail
*/
frontendEndpoint?: Array<string>;
/**
*
* @type {string}
* @memberof ShareDetail
*/
backendEndpoint?: string;
/**
*
* @type {boolean}
* @memberof ShareDetail
*/
closed?: boolean;
/**
*
* @type {string}
* @memberof ShareDetail
*/
status?: string;
}
/**
* Check if a given object implements the ShareDetail interface.
*/
export function instanceOfShareDetail(value: object): value is ShareDetail {
return true;
}
export function ShareDetailFromJSON(json: any): ShareDetail {
return ShareDetailFromJSONTyped(json, false);
}
export function ShareDetailFromJSONTyped(json: any, ignoreDiscriminator: boolean): ShareDetail {
if (json == null) {
return json;
}
return {
'token': json['token'] == null ? undefined : json['token'],
'shareMode': json['shareMode'] == null ? undefined : json['shareMode'],
'backendMode': json['backendMode'] == null ? undefined : json['backendMode'],
'reserved': json['reserved'] == null ? undefined : json['reserved'],
'frontendEndpoint': json['frontendEndpoint'] == null ? undefined : json['frontendEndpoint'],
'backendEndpoint': json['backendEndpoint'] == null ? undefined : json['backendEndpoint'],
'closed': json['closed'] == null ? undefined : json['closed'],
'status': json['status'] == null ? undefined : json['status'],
};
}
export function ShareDetailToJSON(value?: ShareDetail | null): any {
if (value == null) {
return value;
}
return {
'token': value['token'],
'shareMode': value['shareMode'],
'backendMode': value['backendMode'],
'reserved': value['reserved'],
'frontendEndpoint': value['frontendEndpoint'],
'backendEndpoint': value['backendEndpoint'],
'closed': value['closed'],
'status': value['status'],
};
}

View File

@ -0,0 +1,60 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface SharePrivateResponse
*/
export interface SharePrivateResponse {
/**
*
* @type {string}
* @memberof SharePrivateResponse
*/
token?: string;
}
/**
* Check if a given object implements the SharePrivateResponse interface.
*/
export function instanceOfSharePrivateResponse(value: object): value is SharePrivateResponse {
return true;
}
export function SharePrivateResponseFromJSON(json: any): SharePrivateResponse {
return SharePrivateResponseFromJSONTyped(json, false);
}
export function SharePrivateResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): SharePrivateResponse {
if (json == null) {
return json;
}
return {
'token': json['token'] == null ? undefined : json['token'],
};
}
export function SharePrivateResponseToJSON(value?: SharePrivateResponse | null): any {
if (value == null) {
return value;
}
return {
'token': value['token'],
};
}

View File

@ -0,0 +1,68 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface SharePublicResponse
*/
export interface SharePublicResponse {
/**
*
* @type {string}
* @memberof SharePublicResponse
*/
token?: string;
/**
*
* @type {Array<string>}
* @memberof SharePublicResponse
*/
frontendEndpoints?: Array<string>;
}
/**
* Check if a given object implements the SharePublicResponse interface.
*/
export function instanceOfSharePublicResponse(value: object): value is SharePublicResponse {
return true;
}
export function SharePublicResponseFromJSON(json: any): SharePublicResponse {
return SharePublicResponseFromJSONTyped(json, false);
}
export function SharePublicResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): SharePublicResponse {
if (json == null) {
return json;
}
return {
'token': json['token'] == null ? undefined : json['token'],
'frontendEndpoints': json['frontendEndpoints'] == null ? undefined : json['frontendEndpoints'],
};
}
export function SharePublicResponseToJSON(value?: SharePublicResponse | null): any {
if (value == null) {
return value;
}
return {
'token': value['token'],
'frontendEndpoints': value['frontendEndpoints'],
};
}

View File

@ -0,0 +1,92 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface ShareReservedResponse
*/
export interface ShareReservedResponse {
/**
*
* @type {string}
* @memberof ShareReservedResponse
*/
token?: string;
/**
*
* @type {string}
* @memberof ShareReservedResponse
*/
backendMode?: string;
/**
*
* @type {string}
* @memberof ShareReservedResponse
*/
shareMode?: string;
/**
*
* @type {Array<string>}
* @memberof ShareReservedResponse
*/
frontendEndpoints?: Array<string>;
/**
*
* @type {string}
* @memberof ShareReservedResponse
*/
target?: string;
}
/**
* Check if a given object implements the ShareReservedResponse interface.
*/
export function instanceOfShareReservedResponse(value: object): value is ShareReservedResponse {
return true;
}
export function ShareReservedResponseFromJSON(json: any): ShareReservedResponse {
return ShareReservedResponseFromJSONTyped(json, false);
}
export function ShareReservedResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): ShareReservedResponse {
if (json == null) {
return json;
}
return {
'token': json['token'] == null ? undefined : json['token'],
'backendMode': json['backendMode'] == null ? undefined : json['backendMode'],
'shareMode': json['shareMode'] == null ? undefined : json['shareMode'],
'frontendEndpoints': json['frontendEndpoints'] == null ? undefined : json['frontendEndpoints'],
'target': json['target'] == null ? undefined : json['target'],
};
}
export function ShareReservedResponseToJSON(value?: ShareReservedResponse | null): any {
if (value == null) {
return value;
}
return {
'token': value['token'],
'backendMode': value['backendMode'],
'shareMode': value['shareMode'],
'frontendEndpoints': value['frontendEndpoints'],
'target': value['target'],
};
}

View File

@ -0,0 +1,81 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
import type { AccessDetail } from './AccessDetail';
import {
AccessDetailFromJSON,
AccessDetailFromJSONTyped,
AccessDetailToJSON,
} from './AccessDetail';
import type { ShareDetail } from './ShareDetail';
import {
ShareDetailFromJSON,
ShareDetailFromJSONTyped,
ShareDetailToJSON,
} from './ShareDetail';
/**
*
* @export
* @interface StatusResponse
*/
export interface StatusResponse {
/**
*
* @type {Array<AccessDetail>}
* @memberof StatusResponse
*/
accesses?: Array<AccessDetail>;
/**
*
* @type {Array<ShareDetail>}
* @memberof StatusResponse
*/
shares?: Array<ShareDetail>;
}
/**
* Check if a given object implements the StatusResponse interface.
*/
export function instanceOfStatusResponse(value: object): value is StatusResponse {
return true;
}
export function StatusResponseFromJSON(json: any): StatusResponse {
return StatusResponseFromJSONTyped(json, false);
}
export function StatusResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): StatusResponse {
if (json == null) {
return json;
}
return {
'accesses': json['accesses'] == null ? undefined : ((json['accesses'] as Array<any>).map(AccessDetailFromJSON)),
'shares': json['shares'] == null ? undefined : ((json['shares'] as Array<any>).map(ShareDetailFromJSON)),
};
}
export function StatusResponseToJSON(value?: StatusResponse | null): any {
if (value == null) {
return value;
}
return {
'accesses': value['accesses'] == null ? undefined : ((value['accesses'] as Array<any>).map(AccessDetailToJSON)),
'shares': value['shares'] == null ? undefined : ((value['shares'] as Array<any>).map(ShareDetailToJSON)),
};
}

View File

@ -0,0 +1,68 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface VersionResponse
*/
export interface VersionResponse {
/**
*
* @type {string}
* @memberof VersionResponse
*/
v?: string;
/**
*
* @type {string}
* @memberof VersionResponse
*/
consoleEndpoint?: string;
}
/**
* Check if a given object implements the VersionResponse interface.
*/
export function instanceOfVersionResponse(value: object): value is VersionResponse {
return true;
}
export function VersionResponseFromJSON(json: any): VersionResponse {
return VersionResponseFromJSONTyped(json, false);
}
export function VersionResponseFromJSONTyped(json: any, ignoreDiscriminator: boolean): VersionResponse {
if (json == null) {
return json;
}
return {
'v': json['v'] == null ? undefined : json['v'],
'consoleEndpoint': json['consoleEndpoint'] == null ? undefined : json['consoleEndpoint'],
};
}
export function VersionResponseToJSON(value?: VersionResponse | null): any {
if (value == null) {
return value;
}
return {
'v': value['v'],
'consoleEndpoint': value['consoleEndpoint'],
};
}

View File

@ -0,0 +1,12 @@
/* tslint:disable */
/* eslint-disable */
export * from './AccessDetail';
export * from './AccessPrivateResponse';
export * from './ProtobufAny';
export * from './RpcStatus';
export * from './ShareDetail';
export * from './SharePrivateResponse';
export * from './SharePublicResponse';
export * from './ShareReservedResponse';
export * from './StatusResponse';
export * from './VersionResponse';

View File

@ -0,0 +1,426 @@
/* tslint:disable */
/* eslint-disable */
/**
* agent/agentGrpc/agent.proto
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
*
* The version of the OpenAPI document: version not set
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
export const BASE_PATH = "http://localhost".replace(/\/+$/, "");
export interface ConfigurationParameters {
basePath?: string; // override base path
fetchApi?: FetchAPI; // override for fetch implementation
middleware?: Middleware[]; // middleware to apply before/after fetch requests
queryParamsStringify?: (params: HTTPQuery) => string; // stringify function for query strings
username?: string; // parameter for basic security
password?: string; // parameter for basic security
apiKey?: string | Promise<string> | ((name: string) => string | Promise<string>); // parameter for apiKey security
accessToken?: string | Promise<string> | ((name?: string, scopes?: string[]) => string | Promise<string>); // parameter for oauth2 security
headers?: HTTPHeaders; //header params we want to use on every request
credentials?: RequestCredentials; //value for the credentials param we want to use on each request
}
export class Configuration {
constructor(private configuration: ConfigurationParameters = {}) {}
set config(configuration: Configuration) {
this.configuration = configuration;
}
get basePath(): string {
return this.configuration.basePath != null ? this.configuration.basePath : BASE_PATH;
}
get fetchApi(): FetchAPI | undefined {
return this.configuration.fetchApi;
}
get middleware(): Middleware[] {
return this.configuration.middleware || [];
}
get queryParamsStringify(): (params: HTTPQuery) => string {
return this.configuration.queryParamsStringify || querystring;
}
get username(): string | undefined {
return this.configuration.username;
}
get password(): string | undefined {
return this.configuration.password;
}
get apiKey(): ((name: string) => string | Promise<string>) | undefined {
const apiKey = this.configuration.apiKey;
if (apiKey) {
return typeof apiKey === 'function' ? apiKey : () => apiKey;
}
return undefined;
}
get accessToken(): ((name?: string, scopes?: string[]) => string | Promise<string>) | undefined {
const accessToken = this.configuration.accessToken;
if (accessToken) {
return typeof accessToken === 'function' ? accessToken : async () => accessToken;
}
return undefined;
}
get headers(): HTTPHeaders | undefined {
return this.configuration.headers;
}
get credentials(): RequestCredentials | undefined {
return this.configuration.credentials;
}
}
export const DefaultConfig = new Configuration();
/**
* This is the base class for all generated API classes.
*/
export class BaseAPI {
private static readonly jsonRegex = new RegExp('^(:?application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(:?;.*)?$', 'i');
private middleware: Middleware[];
constructor(protected configuration = DefaultConfig) {
this.middleware = configuration.middleware;
}
withMiddleware<T extends BaseAPI>(this: T, ...middlewares: Middleware[]) {
const next = this.clone<T>();
next.middleware = next.middleware.concat(...middlewares);
return next;
}
withPreMiddleware<T extends BaseAPI>(this: T, ...preMiddlewares: Array<Middleware['pre']>) {
const middlewares = preMiddlewares.map((pre) => ({ pre }));
return this.withMiddleware<T>(...middlewares);
}
withPostMiddleware<T extends BaseAPI>(this: T, ...postMiddlewares: Array<Middleware['post']>) {
const middlewares = postMiddlewares.map((post) => ({ post }));
return this.withMiddleware<T>(...middlewares);
}
/**
* Check if the given MIME is a JSON MIME.
* JSON MIME examples:
* application/json
* application/json; charset=UTF8
* APPLICATION/JSON
* application/vnd.company+json
* @param mime - MIME (Multipurpose Internet Mail Extensions)
* @return True if the given MIME is JSON, false otherwise.
*/
protected isJsonMime(mime: string | null | undefined): boolean {
if (!mime) {
return false;
}
return BaseAPI.jsonRegex.test(mime);
}
protected async request(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction): Promise<Response> {
const { url, init } = await this.createFetchParams(context, initOverrides);
const response = await this.fetchApi(url, init);
if (response && (response.status >= 200 && response.status < 300)) {
return response;
}
throw new ResponseError(response, 'Response returned an error code');
}
private async createFetchParams(context: RequestOpts, initOverrides?: RequestInit | InitOverrideFunction) {
let url = this.configuration.basePath + context.path;
if (context.query !== undefined && Object.keys(context.query).length !== 0) {
// only add the querystring to the URL if there are query parameters.
// this is done to avoid urls ending with a "?" character which buggy webservers
// do not handle correctly sometimes.
url += '?' + this.configuration.queryParamsStringify(context.query);
}
const headers = Object.assign({}, this.configuration.headers, context.headers);
Object.keys(headers).forEach(key => headers[key] === undefined ? delete headers[key] : {});
const initOverrideFn =
typeof initOverrides === "function"
? initOverrides
: async () => initOverrides;
const initParams = {
method: context.method,
headers,
body: context.body,
credentials: this.configuration.credentials,
};
const overriddenInit: RequestInit = {
...initParams,
...(await initOverrideFn({
init: initParams,
context,
}))
};
let body: any;
if (isFormData(overriddenInit.body)
|| (overriddenInit.body instanceof URLSearchParams)
|| isBlob(overriddenInit.body)) {
body = overriddenInit.body;
} else if (this.isJsonMime(headers['Content-Type'])) {
body = JSON.stringify(overriddenInit.body);
} else {
body = overriddenInit.body;
}
const init: RequestInit = {
...overriddenInit,
body
};
return { url, init };
}
private fetchApi = async (url: string, init: RequestInit) => {
let fetchParams = { url, init };
for (const middleware of this.middleware) {
if (middleware.pre) {
fetchParams = await middleware.pre({
fetch: this.fetchApi,
...fetchParams,
}) || fetchParams;
}
}
let response: Response | undefined = undefined;
try {
response = await (this.configuration.fetchApi || fetch)(fetchParams.url, fetchParams.init);
} catch (e) {
for (const middleware of this.middleware) {
if (middleware.onError) {
response = await middleware.onError({
fetch: this.fetchApi,
url: fetchParams.url,
init: fetchParams.init,
error: e,
response: response ? response.clone() : undefined,
}) || response;
}
}
if (response === undefined) {
if (e instanceof Error) {
throw new FetchError(e, 'The request failed and the interceptors did not return an alternative response');
} else {
throw e;
}
}
}
for (const middleware of this.middleware) {
if (middleware.post) {
response = await middleware.post({
fetch: this.fetchApi,
url: fetchParams.url,
init: fetchParams.init,
response: response.clone(),
}) || response;
}
}
return response;
}
/**
* Create a shallow clone of `this` by constructing a new instance
* and then shallow cloning data members.
*/
private clone<T extends BaseAPI>(this: T): T {
const constructor = this.constructor as any;
const next = new constructor(this.configuration);
next.middleware = this.middleware.slice();
return next;
}
};
function isBlob(value: any): value is Blob {
return typeof Blob !== 'undefined' && value instanceof Blob;
}
function isFormData(value: any): value is FormData {
return typeof FormData !== "undefined" && value instanceof FormData;
}
export class ResponseError extends Error {
override name: "ResponseError" = "ResponseError";
constructor(public response: Response, msg?: string) {
super(msg);
}
}
export class FetchError extends Error {
override name: "FetchError" = "FetchError";
constructor(public cause: Error, msg?: string) {
super(msg);
}
}
export class RequiredError extends Error {
override name: "RequiredError" = "RequiredError";
constructor(public field: string, msg?: string) {
super(msg);
}
}
export const COLLECTION_FORMATS = {
csv: ",",
ssv: " ",
tsv: "\t",
pipes: "|",
};
export type FetchAPI = WindowOrWorkerGlobalScope['fetch'];
export type Json = any;
export type HTTPMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
export type HTTPHeaders = { [key: string]: string };
export type HTTPQuery = { [key: string]: string | number | null | boolean | Array<string | number | null | boolean> | Set<string | number | null | boolean> | HTTPQuery };
export type HTTPBody = Json | FormData | URLSearchParams;
export type HTTPRequestInit = { headers?: HTTPHeaders; method: HTTPMethod; credentials?: RequestCredentials; body?: HTTPBody };
export type ModelPropertyNaming = 'camelCase' | 'snake_case' | 'PascalCase' | 'original';
export type InitOverrideFunction = (requestContext: { init: HTTPRequestInit, context: RequestOpts }) => Promise<RequestInit>
export interface FetchParams {
url: string;
init: RequestInit;
}
export interface RequestOpts {
path: string;
method: HTTPMethod;
headers: HTTPHeaders;
query?: HTTPQuery;
body?: HTTPBody;
}
export function querystring(params: HTTPQuery, prefix: string = ''): string {
return Object.keys(params)
.map(key => querystringSingleKey(key, params[key], prefix))
.filter(part => part.length > 0)
.join('&');
}
function querystringSingleKey(key: string, value: string | number | null | undefined | boolean | Array<string | number | null | boolean> | Set<string | number | null | boolean> | HTTPQuery, keyPrefix: string = ''): string {
const fullKey = keyPrefix + (keyPrefix.length ? `[${key}]` : key);
if (value instanceof Array) {
const multiValue = value.map(singleValue => encodeURIComponent(String(singleValue)))
.join(`&${encodeURIComponent(fullKey)}=`);
return `${encodeURIComponent(fullKey)}=${multiValue}`;
}
if (value instanceof Set) {
const valueAsArray = Array.from(value);
return querystringSingleKey(key, valueAsArray, keyPrefix);
}
if (value instanceof Date) {
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`;
}
if (value instanceof Object) {
return querystring(value as HTTPQuery, fullKey);
}
return `${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`;
}
export function mapValues(data: any, fn: (item: any) => any) {
return Object.keys(data).reduce(
(acc, key) => ({ ...acc, [key]: fn(data[key]) }),
{}
);
}
export function canConsumeForm(consumes: Consume[]): boolean {
for (const consume of consumes) {
if ('multipart/form-data' === consume.contentType) {
return true;
}
}
return false;
}
export interface Consume {
contentType: string;
}
export interface RequestContext {
fetch: FetchAPI;
url: string;
init: RequestInit;
}
export interface ResponseContext {
fetch: FetchAPI;
url: string;
init: RequestInit;
response: Response;
}
export interface ErrorContext {
fetch: FetchAPI;
url: string;
init: RequestInit;
error: unknown;
response?: Response;
}
export interface Middleware {
pre?(context: RequestContext): Promise<FetchParams | void>;
post?(context: ResponseContext): Promise<Response | void>;
onError?(context: ErrorContext): Promise<Response | void>;
}
export interface ApiResponse<T> {
raw: Response;
value(): Promise<T>;
}
export interface ResponseTransformer<T> {
(json: any): T;
}
export class JSONApiResponse<T> {
constructor(public raw: Response, private transformer: ResponseTransformer<T> = (jsonValue: any) => jsonValue) {}
async value(): Promise<T> {
return this.transformer(await this.raw.json());
}
}
export class VoidApiResponse {
constructor(public raw: Response) {}
async value(): Promise<void> {
return undefined;
}
}
export class BlobApiResponse {
constructor(public raw: Response) {}
async value(): Promise<Blob> {
return await this.raw.blob();
};
}
export class TextApiResponse {
constructor(public raw: Response) {}
async value(): Promise<string> {
return await this.raw.text();
};
}

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="125.797mm"
height="166.26598mm"
viewBox="0 0 125.797 166.26598"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.4 (e7c3feb, 2024-10-09)"
sodipodi:docname="zrok-1.0.0-rocket-white.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showguides="false"
inkscape:zoom="0.85634716"
inkscape:cx="560.52034"
inkscape:cy="509.72318"
inkscape:window-width="1952"
inkscape:window-height="1304"
inkscape:window-x="1311"
inkscape:window-y="48"
inkscape:window-maximized="0"
inkscape:current-layer="layer1"><inkscape:page
x="0"
y="-4.4822158e-22"
width="125.797"
height="166.26598"
id="page2"
margin="0"
bleed="0" /></sodipodi:namedview><defs
id="defs1" /><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-41.620475,-64.027978)"><path
id="path2"
style="fill:#9bf316;fill-opacity:1;stroke-width:0.865487"
d="m 104.52059,64.027974 c 0,0 -12.300998,16.684095 -17.163248,24.964306 -4.8623,8.28022 -7.86765,12.84754 -10.59501,26.3339 -2.72736,13.48636 -1.27406,42.21319 -1.27406,42.21319 l -18.58752,20.04004 -15.280273,49.9615 40.422833,-6.79427 a 22.714797,11.567473 0 0 0 22.320548,9.54731 22.714797,11.567473 0 0 0 22.32712,-9.55945 l 40.72649,6.84277 -15.28027,-49.95979 -18.58916,-20.04001 c 0,0 1.45496,-28.72857 -1.2724,-42.21493 -2.72736,-13.48636 -5.73437,-18.05368 -10.59667,-26.3339 -4.8608,-8.277646 -17.14905,-24.947062 -17.15668,-24.957378 z m -0.0151,14.741718 c 0.52421,0.860497 14.76063,18.300498 18.34492,32.586238 3.65093,14.55125 3.25036,30.16797 2.29067,46.75483 -0.68395,11.82081 -5.48912,37.13724 -8.2384,50.97445 a 22.714797,11.567473 0 0 0 -12.54073,-1.9254 22.714797,11.567473 0 0 0 -12.237098,1.84921 c -2.75047,-13.84452 -7.55003,-39.12307 -8.23343,-50.93462 -0.95969,-16.58687 -1.36026,-32.20531 2.29067,-46.75656 3.57561,-14.25109 17.733538,-31.579359 18.323398,-32.548148 z m -27.999198,95.069708 6.36686,35.53319 -30.30472,9.08328 10.94985,-35.7998 z m 56.021568,0.0351 12.988,8.81667 10.9482,35.80155 -30.30311,-9.08504 z"
inkscape:export-filename="zrok-1.0.0-rocket-white.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" /></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,55 @@
body {
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding-bottom: 15px;
min-width: 320px;
min-height: 100vh;
}
code {
font-family: 'JetBrains Mono', sans-serif;
}
a {
font-weight: 500;
color: #241775;
text-decoration: inherit;
}
a:hover {
color: #9bf316;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
}
#footer {
text-align: center;
}

View File

@ -0,0 +1,14 @@
import "./index.css";
import {StrictMode} from "react";
import {createRoot} from "react-dom/client";
import {ThemeProvider} from "@mui/material";
import {theme} from "./model/theme.ts";
import AgentUi from "./AgentUi.tsx";
createRoot(document.getElementById('root')!).render(
<StrictMode>
<ThemeProvider theme={theme}>
<AgentUi />
</ThemeProvider>
</StrictMode>
);

View File

@ -0,0 +1,5 @@
import {AgentApi, Configuration} from "../api";
export const GetAgentApi = () => {
return new AgentApi(new Configuration({basePath: window.location.origin}));
}

View File

@ -0,0 +1,36 @@
import {AccessDetail, ShareDetail, StatusResponse} from "../api";
export class AgentObject {
type: string;
id: string;
v: (ShareDetail|AccessDetail);
}
export function buildOverview(status: StatusResponse): Array<AgentObject> {
let out = new Array<AgentObject>();
if(status) {
if(status.accesses) {
status.accesses.forEach(acc => {
let accObj = new AgentObject();
accObj.type = "access";
accObj.id = acc.frontendToken!;
accObj.v = acc;
out.push(accObj);
});
}
if(status.shares) {
status.shares.forEach(shr => {
let shrObj = new AgentObject();
shrObj.type = "share";
shrObj.id = shr.token!;
shrObj.v = shr;
out.push(shrObj);
});
}
out.sort((a, b) => {
if(a.id < b.id) return -1;
if(a.id > b.id) return 1;
});
}
return out;
}

View File

@ -0,0 +1,47 @@
import {createTheme} from "@mui/material";
const componentOptions = {
MuiCard: {
styleOverrides: {
root: ({theme}) => theme.unstable_sx({
mt: 5,
p: 1,
borderRadius: 3,
}),
}
},
MuiAppBar: {
styleOverrides: {
root : ({theme}) => theme.unstable_sx({
borderRadius: 3,
}),
}
}
}
export const theme = createTheme({
components: componentOptions,
palette: {
mode: 'light',
primary: {
main: '#241775',
},
secondary: {
main: '#9bf316',
},
},
typography: {
fontFamily: 'Poppins',
},
})
export const modalStyle = {
position: 'absolute',
top: '25%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 600,
bgcolor: 'background.paper',
boxShadow: 24,
p: 4,
};

1
agent/agentUi/src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}

View File

@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,15 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/v1': {
target: 'http://localhost:8888',
changeOrigin: true,
}
}
}
})

15
agent/config.go Normal file
View File

@ -0,0 +1,15 @@
package agent
type AgentConfig struct {
ConsoleAddress string
ConsoleStartPort uint16
ConsoleEndPort uint16
}
func DefaultConfig() *AgentConfig {
return &AgentConfig{
ConsoleAddress: "127.0.0.1",
ConsoleStartPort: 8080,
ConsoleEndPort: 8181,
}
}

View File

@ -0,0 +1,59 @@
//go:build !windows
package proctree
import (
"os/exec"
"sync"
)
func Init(_ string) error {
return nil
}
func StartChild(tail TailFunction, args ...string) (*Child, error) {
cmd := exec.Command(args[0], args[1:]...)
cld := &Child{
TailFunction: tail,
cmd: cmd,
outStream: make(chan []byte),
errStream: make(chan []byte),
wg: new(sync.WaitGroup),
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}
cld.wg.Add(3)
go reader(stdout, cld.outStream, cld.wg)
go reader(stderr, cld.errStream, cld.wg)
go cld.combiner(cld.wg)
return cld, nil
}
func WaitChild(c *Child) error {
c.wg.Wait()
if err := c.cmd.Wait(); err != nil {
return err
}
return nil
}
func StopChild(c *Child) error {
if err := c.cmd.Process.Kill(); err != nil {
return err
}
return nil
}

79
agent/proctree/impl_windows.go Executable file
View File

@ -0,0 +1,79 @@
//go:build windows
package proctree
import (
"github.com/kolesnikovae/go-winjob"
"golang.org/x/sys/windows"
"os/exec"
"sync"
)
var job *winjob.JobObject
func Init(name string) error {
var err error
if job == nil {
job, err = winjob.Create(name, winjob.LimitKillOnJobClose, winjob.LimitBreakawayOK)
if err != nil {
return err
}
}
return nil
}
func StartChild(tail TailFunction, args ...string) (*Child, error) {
cmd := exec.Command(args[0], args[1:]...)
cmd.SysProcAttr = &windows.SysProcAttr{CreationFlags: windows.CREATE_SUSPENDED}
cld := &Child{
TailFunction: tail,
cmd: cmd,
outStream: make(chan []byte),
errStream: make(chan []byte),
wg: new(sync.WaitGroup),
}
stdout, err := cmd.StdoutPipe()
if err != nil {
return nil, err
}
stderr, err := cmd.StderrPipe()
if err != nil {
return nil, err
}
if err := cmd.Start(); err != nil {
return nil, err
}
if err := job.Assign(cmd.Process); err != nil {
return nil, err
}
if err := winjob.ResumeProcess(cmd.Process.Pid); err != nil {
return nil, err
}
cld.wg.Add(3)
go reader(stdout, cld.outStream, cld.wg)
go reader(stderr, cld.errStream, cld.wg)
go cld.combiner(cld.wg)
return cld, nil
}
func WaitChild(c *Child) error {
c.wg.Wait()
if err := c.cmd.Wait(); err != nil {
return err
}
return nil
}
func StopChild(c *Child) error {
if err := c.cmd.Process.Kill(); err != nil {
return err
}
return nil
}

67
agent/proctree/proctree.go Executable file
View File

@ -0,0 +1,67 @@
package proctree
import (
"fmt"
_ "github.com/kolesnikovae/go-winjob"
"io"
"os/exec"
"sync"
)
type Child struct {
TailFunction TailFunction
cmd *exec.Cmd
outStream chan []byte
errStream chan []byte
wg *sync.WaitGroup
}
type TailFunction func(data []byte)
func (c *Child) combiner(wg *sync.WaitGroup) {
defer wg.Done()
outDone := false
errDone := false
for {
select {
case data := <-c.outStream:
if data != nil {
if c.TailFunction != nil {
c.TailFunction(data)
}
} else {
outDone = true
}
case data := <-c.errStream:
if data != nil {
if c.TailFunction != nil {
c.TailFunction(data)
}
} else {
errDone = true
}
}
if outDone && errDone {
return
}
}
}
func reader(r io.ReadCloser, o chan []byte, wg *sync.WaitGroup) {
defer close(o)
defer wg.Done()
buf := make([]byte, 64*1024)
for {
n, err := r.Read(buf)
if err != nil {
if err == io.EOF {
return
}
fmt.Printf("error reading: %v", err)
return
}
o <- buf[:n]
}
}

19
agent/releaseAccess.go Normal file
View File

@ -0,0 +1,19 @@
package agent
import (
"context"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
func (i *agentGrpcImpl) ReleaseAccess(_ context.Context, req *agentGrpc.ReleaseAccessRequest) (*agentGrpc.ReleaseAccessResponse, error) {
if acc, found := i.agent.accesses[req.FrontendToken]; found {
i.agent.rmAccess <- acc
logrus.Infof("released access '%v'", acc.frontendToken)
} else {
return nil, errors.Errorf("agent has no access with frontend token '%v'", req.FrontendToken)
}
return nil, nil
}

19
agent/releaseShare.go Executable file
View File

@ -0,0 +1,19 @@
package agent
import (
"context"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
func (i *agentGrpcImpl) ReleaseShare(_ context.Context, req *agentGrpc.ReleaseShareRequest) (*agentGrpc.ReleaseShareResponse, error) {
if shr, found := i.agent.shares[req.Token]; found {
i.agent.rmShare <- shr
logrus.Infof("released share '%v'", shr.token)
} else {
return nil, errors.Errorf("agent has no share with token '%v'", req.Token)
}
return nil, nil
}

83
agent/share.go Normal file
View File

@ -0,0 +1,83 @@
package agent
import (
"errors"
"github.com/michaelquigley/pfxlog"
"github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/sdk/golang/sdk"
"time"
)
type share struct {
token string
frontendEndpoints []string
target string
basicAuth []string
frontendSelection []string
shareMode sdk.ShareMode
backendMode sdk.BackendMode
reserved bool
insecure bool
oauthProvider string
oauthEmailAddressPatterns []string
oauthCheckInterval time.Duration
closed bool
accessGrants []string
process *proctree.Child
sub *subordinate.MessageHandler
agent *Agent
}
func (s *share) monitor() {
if err := proctree.WaitChild(s.process); err != nil {
pfxlog.ChannelLogger(s.token).Error(err)
}
s.agent.rmShare <- s
}
func (s *share) bootHandler(msgType string, msg subordinate.Message) error {
switch msgType {
case subordinate.BootMessage:
if v, found := msg["token"]; found {
if str, ok := v.(string); ok {
s.token = str
}
}
if v, found := msg["backend_mode"]; found {
if str, ok := v.(string); ok {
s.backendMode = sdk.BackendMode(str)
}
}
if v, found := msg["share_mode"]; found {
if str, ok := v.(string); ok {
s.shareMode = sdk.ShareMode(str)
}
}
if v, found := msg["frontend_endpoints"]; found {
if vArr, ok := v.([]interface{}); ok {
for _, v := range vArr {
if str, ok := v.(string); ok {
s.frontendEndpoints = append(s.frontendEndpoints, str)
}
}
}
}
if v, found := msg["target"]; found {
if str, ok := v.(string); ok {
s.target = str
}
}
case subordinate.ErrorMessage:
if v, found := msg[subordinate.ErrorMessage]; found {
if str, ok := v.(string); ok {
return errors.New(str)
}
}
}
return nil
}

82
agent/sharePrivate.go Normal file
View File

@ -0,0 +1,82 @@
package agent
import (
"context"
"errors"
"fmt"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/sdk/golang/sdk"
"github.com/sirupsen/logrus"
"os"
)
func (i *agentGrpcImpl) SharePrivate(_ context.Context, req *agentGrpc.SharePrivateRequest) (*agentGrpc.SharePrivateResponse, error) {
root, err := environment.LoadRoot()
if err != nil {
return nil, err
}
if !root.IsEnabled() {
return nil, errors.New("unable to load environment; did you 'zrok enable'?")
}
shrCmd := []string{os.Args[0], "share", "private", "--subordinate", "-b", req.BackendMode}
shr := &share{
shareMode: sdk.PrivateShareMode,
backendMode: sdk.BackendMode(req.BackendMode),
sub: subordinate.NewMessageHandler(),
agent: i.agent,
}
shr.sub.MessageHandler = func(msg subordinate.Message) {
logrus.Info(msg)
}
var bootErr error
shr.sub.BootHandler = func(msgType string, msg subordinate.Message) {
bootErr = shr.bootHandler(msgType, msg)
}
shr.sub.MalformedHandler = func(msg subordinate.Message) {
logrus.Error(msg)
}
if req.Insecure {
shrCmd = append(shrCmd, "--insecure")
}
shr.insecure = req.Insecure
if req.Closed {
shrCmd = append(shrCmd, "--closed")
}
shr.closed = req.Closed
for _, grant := range req.AccessGrants {
shrCmd = append(shrCmd, "--access-grant", grant)
}
shr.accessGrants = req.AccessGrants
shrCmd = append(shrCmd, req.Target)
shr.target = req.Target
logrus.Infof("executing '%v'", shrCmd)
shr.process, err = proctree.StartChild(shr.sub.Tail, shrCmd...)
if err != nil {
return nil, err
}
<-shr.sub.BootComplete
if bootErr == nil {
go shr.monitor()
i.agent.addShare <- shr
return &agentGrpc.SharePrivateResponse{Token: shr.token}, nil
} else {
if err := proctree.WaitChild(shr.process); err != nil {
logrus.Errorf("error joining: %v", err)
}
return nil, fmt.Errorf("unable to start share: %v", bootErr)
}
}

109
agent/sharePublic.go Normal file
View File

@ -0,0 +1,109 @@
package agent
import (
"context"
"errors"
"fmt"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/sdk/golang/sdk"
"github.com/sirupsen/logrus"
"os"
)
func (i *agentGrpcImpl) SharePublic(_ context.Context, req *agentGrpc.SharePublicRequest) (*agentGrpc.SharePublicResponse, error) {
root, err := environment.LoadRoot()
if err != nil {
return nil, err
}
if !root.IsEnabled() {
return nil, errors.New("unable to load environment; did you 'zrok enable'?")
}
shrCmd := []string{os.Args[0], "share", "public", "--subordinate", "-b", req.BackendMode}
shr := &share{
shareMode: sdk.PublicShareMode,
backendMode: sdk.BackendMode(req.BackendMode),
sub: subordinate.NewMessageHandler(),
agent: i.agent,
}
shr.sub.MessageHandler = func(msg subordinate.Message) {
logrus.Info(msg)
}
var bootErr error
shr.sub.BootHandler = func(msgType string, msg subordinate.Message) {
bootErr = shr.bootHandler(msgType, msg)
}
shr.sub.MalformedHandler = func(msg subordinate.Message) {
logrus.Error(msg)
}
for _, basicAuth := range req.BasicAuth {
shrCmd = append(shrCmd, "--basic-auth", basicAuth)
}
shr.basicAuth = req.BasicAuth
for _, frontendSelection := range req.FrontendSelection {
shrCmd = append(shrCmd, "--frontend", frontendSelection)
}
shr.frontendSelection = req.FrontendSelection
if req.Insecure {
shrCmd = append(shrCmd, "--insecure")
}
shr.insecure = req.Insecure
if req.OauthProvider != "" {
shrCmd = append(shrCmd, "--oauth-provider", req.OauthProvider)
}
shr.oauthProvider = req.OauthProvider
for _, pattern := range req.OauthEmailAddressPatterns {
shrCmd = append(shrCmd, "--oauth-email-address-patterns", pattern)
}
shr.oauthEmailAddressPatterns = req.OauthEmailAddressPatterns
if req.OauthCheckInterval != "" {
shrCmd = append(shrCmd, "--oauth-check-interval", req.OauthCheckInterval)
}
if req.Closed {
shrCmd = append(shrCmd, "--closed")
}
shr.closed = req.Closed
for _, grant := range req.AccessGrants {
shrCmd = append(shrCmd, "--access-grant", grant)
}
shr.accessGrants = req.AccessGrants
shrCmd = append(shrCmd, req.Target)
shr.target = req.Target
logrus.Infof("executing '%v'", shrCmd)
shr.process, err = proctree.StartChild(shr.sub.Tail, shrCmd...)
if err != nil {
return nil, err
}
<-shr.sub.BootComplete
if bootErr == nil {
go shr.monitor()
i.agent.addShare <- shr
return &agentGrpc.SharePublicResponse{
Token: shr.token,
FrontendEndpoints: shr.frontendEndpoints,
}, nil
} else {
if err := proctree.WaitChild(shr.process); err != nil {
logrus.Errorf("error joining: %v", err)
}
return nil, fmt.Errorf("unable to start share: %v", bootErr)
}
}

78
agent/shareReserved.go Normal file
View File

@ -0,0 +1,78 @@
package agent
import (
"context"
"errors"
"fmt"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/environment"
"github.com/sirupsen/logrus"
"os"
)
func (i *agentGrpcImpl) ShareReserved(_ context.Context, req *agentGrpc.ShareReservedRequest) (*agentGrpc.ShareReservedResponse, error) {
root, err := environment.LoadRoot()
if err != nil {
return nil, err
}
if !root.IsEnabled() {
return nil, errors.New("unable to load environment; did you 'zrok enable'?")
}
shrCmd := []string{os.Args[0], "share", "reserved", "--subordinate"}
shr := &share{
reserved: true,
sub: subordinate.NewMessageHandler(),
agent: i.agent,
}
shr.sub.MessageHandler = func(msg subordinate.Message) {
logrus.Info(msg)
}
var bootErr error
shr.sub.BootHandler = func(msgType string, msg subordinate.Message) {
bootErr = shr.bootHandler(msgType, msg)
}
shr.sub.MalformedHandler = func(msg subordinate.Message) {
logrus.Error(msg)
}
if req.OverrideEndpoint != "" {
shrCmd = append(shrCmd, "--override-endpoint", req.OverrideEndpoint)
}
if req.Insecure {
shrCmd = append(shrCmd, "--insecure")
}
shr.insecure = req.Insecure
shrCmd = append(shrCmd, req.Token)
shr.token = req.Token
shr.process, err = proctree.StartChild(shr.sub.Tail, shrCmd...)
if err != nil {
return nil, err
}
<-shr.sub.BootComplete
if bootErr == nil {
go shr.monitor()
i.agent.addShare <- shr
return &agentGrpc.ShareReservedResponse{
Token: shr.token,
BackendMode: string(shr.backendMode),
ShareMode: string(shr.shareMode),
FrontendEndpoints: shr.frontendEndpoints,
Target: shr.target,
}, nil
} else {
if err := proctree.WaitChild(shr.process); err != nil {
logrus.Errorf("error joining: %v", err)
}
return nil, fmt.Errorf("unable to start share: %v", bootErr)
}
}

40
agent/status.go Normal file
View File

@ -0,0 +1,40 @@
package agent
import (
"context"
"github.com/openziti/zrok/agent/agentGrpc"
"sort"
)
func (i *agentGrpcImpl) Status(_ context.Context, _ *agentGrpc.StatusRequest) (*agentGrpc.StatusResponse, error) {
var accesses []*agentGrpc.AccessDetail
for feToken, acc := range i.agent.accesses {
accesses = append(accesses, &agentGrpc.AccessDetail{
FrontendToken: feToken,
Token: acc.token,
BindAddress: acc.bindAddress,
ResponseHeaders: acc.responseHeaders,
})
}
sort.Slice(accesses, func(i, j int) bool {
return accesses[i].FrontendToken < accesses[j].FrontendToken
})
var shares []*agentGrpc.ShareDetail
for token, shr := range i.agent.shares {
shares = append(shares, &agentGrpc.ShareDetail{
Token: token,
ShareMode: string(shr.shareMode),
BackendMode: string(shr.backendMode),
Reserved: shr.reserved,
FrontendEndpoint: shr.frontendEndpoints,
BackendEndpoint: shr.target,
Closed: shr.closed,
})
}
sort.Slice(shares, func(i, j int) bool {
return shares[i].Token < shares[j].Token
})
return &agentGrpc.StatusResponse{Accesses: accesses, Shares: shares}, nil
}

17
agent/version.go Normal file
View File

@ -0,0 +1,17 @@
package agent
import (
"context"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/build"
"github.com/sirupsen/logrus"
)
func (i *agentGrpcImpl) Version(_ context.Context, _ *agentGrpc.VersionRequest) (*agentGrpc.VersionResponse, error) {
v := build.String()
logrus.Debugf("responding to version inquiry with '%v'", v)
return &agentGrpc.VersionResponse{
V: v,
ConsoleEndpoint: i.agent.httpEndpoint,
}, nil
}

14
bin/generate_pb.sh Executable file
View File

@ -0,0 +1,14 @@
#!/bin/sh
go install \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \
google.golang.org/protobuf/cmd/protoc-gen-go \
google.golang.org/grpc/cmd/protoc-gen-go-grpc
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
--grpc-gateway_out=. --grpc-gateway_opt=paths=source_relative \
--openapiv2_out=. \
agent/agentGrpc/agent.proto

View File

@ -7,11 +7,6 @@ command -v swagger >/dev/null 2>&1 || {
exit 1
}
command -v openapi >/dev/null 2>&1 || {
echo >&2 "command 'openapi' not installed. see: https://www.npmjs.com/package/openapi-client for installation"
exit 1
}
command -v swagger-codegen 2>&1 || {
echo >&2 "command 'swagger-codegen' not installed. see: https://github.com/swagger-api/swagger-codegen for installation"
exit 1
@ -42,13 +37,16 @@ swagger generate server -P rest_model_zrok.Principal -f "$zrokSpec" -s rest_serv
echo "...generating zrok client"
swagger generate client -P rest_model_zrok.Principal -f "$zrokSpec" -c rest_client_zrok -t "$zrokDir" -m "rest_model_zrok"
echo "...generating js client"
openapi -s specs/zrok.yml -o ui/src/api -l js
echo "...generating api console ts client"
openapi-generator-cli generate -i specs/zrok.yml -o ui/src/api -g typescript-fetch
echo "...generating ts client"
echo "...generating agent console ts client"
openapi-generator-cli generate -i agent/agentGrpc/agent.swagger.json -o agent/agentUi/src/api -g typescript-fetch
echo "...generating nodejs sdk ts client"
openapi-generator-cli generate -i specs/zrok.yml -o sdk/nodejs/sdk/src/zrok/api -g typescript-node
echo "...generating python client"
echo "...generating python sdk client"
swagger-codegen generate -i specs/zrok.yml -o sdk/python/sdk/zrok -c $pythonConfig -l python
git checkout rest_server_zrok/configure_zrok.go
git checkout rest_server_zrok/configure_zrok.go

View File

@ -5,7 +5,7 @@ import "fmt"
var Version string
var Hash string
const Series = "v0.4"
const Series = "v1.0"
func String() string {
if Version != "" {

View File

@ -1,19 +1,27 @@
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/endpoints/tcpTunnel"
"github.com/openziti/zrok/endpoints/udpTunnel"
"github.com/openziti/zrok/endpoints/vpn"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/environment/env_core"
"github.com/openziti/zrok/rest_client_zrok"
"github.com/openziti/zrok/rest_client_zrok/share"
"github.com/openziti/zrok/rest_model_zrok"
"github.com/openziti/zrok/tui"
"github.com/openziti/zrok/util"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"net/url"
@ -29,7 +37,14 @@ func init() {
type accessPrivateCommand struct {
bindAddress string
autoMode bool
autoAddress string
autoStartPort uint16
autoEndPort uint16
headless bool
subordinate bool
forceLocal bool
forceAgent bool
responseHeaders []string
cmd *cobra.Command
}
@ -41,47 +56,98 @@ func newAccessPrivateCommand() *accessPrivateCommand {
Args: cobra.ExactArgs(1),
}
command := &accessPrivateCommand{cmd: cmd}
cmd.Flags().BoolVar(&command.headless, "headless", false, "Disable TUI and run headless")
cmd.Flags().StringVarP(&command.bindAddress, "bind", "b", "127.0.0.1:9191", "The address to bind the private frontend")
headless := false
if root, err := environment.LoadRoot(); err == nil {
headless, _ = root.Headless()
}
cmd.Flags().BoolVar(&command.headless, "headless", headless, "Disable TUI and run headless")
cmd.Flags().BoolVar(&command.subordinate, "subordinate", false, "Enable subordinate mode")
cmd.MarkFlagsMutuallyExclusive("headless", "subordinate")
cmd.Flags().BoolVar(&command.forceLocal, "force-local", false, "Skip agent detection and force local mode")
cmd.Flags().BoolVar(&command.forceAgent, "force-agent", false, "Skip agent detection and force agent mode")
cmd.MarkFlagsMutuallyExclusive("force-local", "force-agent")
cmd.Flags().StringVarP(&command.bindAddress, "bind", "b", "127.0.0.1:9191", "The address to bind the private frontend (ignored when using '--auto')")
cmd.Flags().BoolVar(&command.autoMode, "auto", false, "Enable automatic port detection")
cmd.Flags().StringVar(&command.autoAddress, "auto-address", "127.0.0.1", "The address to use for automatic port detection")
cmd.Flags().Uint16Var(&command.autoStartPort, "auto-start-port", 8080, "The starting port to use for automatic port detection")
cmd.Flags().Uint16Var(&command.autoEndPort, "auto-end-port", 8888, "The ending port to use for automatic port detection")
cmd.Flags().StringArrayVar(&command.responseHeaders, "response-header", []string{}, "Add a response header ('key:value')")
cmd.Run = command.run
return command
}
func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
shrToken := args[0]
env, err := environment.LoadRoot()
if err != nil {
tui.Error("error loading environment", err)
if cmd.subordinate {
logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: time.RFC3339Nano})
}
if !env.IsEnabled() {
root, err := environment.LoadRoot()
if err != nil {
cmd.error(err)
}
if !root.IsEnabled() {
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
}
zrok, err := env.Client()
if err != nil {
if !panicInstead {
tui.Error("unable to create zrok client", err)
if cmd.subordinate || cmd.forceLocal {
cmd.accessLocal(args, root)
} else {
agent := cmd.forceAgent
if !cmd.forceAgent {
agent, err = agentClient.IsAgentRunning(root)
if err != nil {
tui.Error("error checking if agent is running", err)
}
}
panic(err)
if agent {
cmd.accessAgent(args, root)
} else {
cmd.accessLocal(args, root)
}
}
}
func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root) {
shrToken := args[0]
zrok, err := root.Client()
if err != nil {
cmd.error(err)
}
auth := httptransport.APIKeyAuth("X-TOKEN", "header", env.Environment().Token)
auth := httptransport.APIKeyAuth("X-TOKEN", "header", root.Environment().Token)
req := share.NewAccessParams()
req.Body = &rest_model_zrok.AccessRequest{
ShrToken: shrToken,
EnvZID: env.Environment().ZitiIdentity,
}
req.Body.ShareToken = shrToken
req.Body.EnvZID = root.Environment().ZitiIdentity
accessResp, err := zrok.Share.Access(req, auth)
if err != nil {
if !panicInstead {
tui.Error("unable to access", err)
}
panic(err)
cmd.error(err)
}
bindAddress := cmd.bindAddress
if cmd.autoMode {
if accessResp.Payload.BackendMode == "udpTunnel" {
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(errors.New("auto-addressing is not compatible with the 'udpTunnel' backend mode"))
}
autoAddress, err := util.AutoListenerAddress("tcp", cmd.autoAddress, cmd.autoStartPort, cmd.autoEndPort)
if err != nil {
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
bindAddress = autoAddress
}
upReq := share.NewUpdateAccessParams()
upReq.Body.FrontendToken = accessResp.Payload.FrontendToken
upReq.Body.BindAddress = bindAddress
_, err = zrok.Share.UpdateAccess(upReq, auth)
if err != nil {
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
logrus.Infof("allocated frontend '%v'", accessResp.Payload.FrontendToken)
protocol := "http://"
switch accessResp.Payload.BackendMode {
@ -91,80 +157,66 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
protocol = "udp://"
}
endpointUrl, err := url.Parse(protocol + cmd.bindAddress)
endpointUrl, err := url.Parse(protocol + bindAddress)
if err != nil {
if !panicInstead {
tui.Error("invalid endpoint address", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
requests := make(chan *endpoints.Request, 1024)
switch accessResp.Payload.BackendMode {
case "tcpTunnel":
fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{
BindAddress: cmd.bindAddress,
IdentityName: env.EnvironmentIdentityName(),
BindAddress: bindAddress,
IdentityName: root.EnvironmentIdentityName(),
ShrToken: args[0],
RequestsChan: requests,
})
if err != nil {
if !panicInstead {
tui.Error("unable to create private access", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
go func() {
if err := fe.Run(); err != nil {
if !panicInstead {
tui.Error("error starting access", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
}()
case "udpTunnel":
fe, err := udpTunnel.NewFrontend(&udpTunnel.FrontendConfig{
BindAddress: cmd.bindAddress,
IdentityName: env.EnvironmentIdentityName(),
IdentityName: root.EnvironmentIdentityName(),
ShrToken: args[0],
RequestsChan: requests,
IdleTime: time.Minute,
})
if err != nil {
if !panicInstead {
tui.Error("unable to create private frontend", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
go func() {
if err := fe.Run(); err != nil {
if !panicInstead {
tui.Error("error starting frontend", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
}()
case "socks":
fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{
BindAddress: cmd.bindAddress,
IdentityName: env.EnvironmentIdentityName(),
BindAddress: bindAddress,
IdentityName: root.EnvironmentIdentityName(),
ShrToken: args[0],
RequestsChan: requests,
})
if err != nil {
if !panicInstead {
tui.Error("unable to create private access", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
go func() {
if err := fe.Run(); err != nil {
if !panicInstead {
tui.Error("error starting access", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
}()
@ -173,55 +225,60 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
Scheme: "VPN",
}
fe, err := vpn.NewFrontend(&vpn.FrontendConfig{
IdentityName: env.EnvironmentIdentityName(),
IdentityName: root.EnvironmentIdentityName(),
ShrToken: args[0],
RequestsChan: requests,
})
if err != nil {
if !panicInstead {
tui.Error("unable to create private access", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
go func() {
if err := fe.Run(); err != nil {
if !panicInstead {
tui.Error("error starting access", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
}()
default:
cfg := proxy.DefaultFrontendConfig(env.EnvironmentIdentityName())
cfg := proxy.DefaultFrontendConfig(root.EnvironmentIdentityName())
cfg.ShrToken = shrToken
cfg.Address = cmd.bindAddress
cfg.Address = bindAddress
cfg.ResponseHeaders = cmd.responseHeaders
cfg.RequestsChan = requests
fe, err := proxy.NewFrontend(cfg)
if err != nil {
if !panicInstead {
tui.Error("unable to create private frontend", err)
}
panic(err)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
go func() {
if err := fe.Run(); err != nil {
if !panicInstead {
tui.Error("unable to run frontend", err)
}
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.error(err)
}
}()
}
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
go func() {
<-c
cmd.destroy(accessResp.Payload.FrontendToken, env.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
os.Exit(0)
}()
if cmd.subordinate {
data := make(map[string]interface{})
data[subordinate.MessageKey] = subordinate.BootMessage
data["frontend_token"] = accessResp.Payload.FrontendToken
data["bind_address"] = bindAddress
jsonData, err := json.Marshal(data)
if err != nil {
subordinateError(err)
}
fmt.Println(string(jsonData))
}
if cmd.headless {
logrus.Infof("access the zrok share at the following endpoint: %v", endpointUrl.String())
for {
@ -230,7 +287,22 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
}
}
} else if cmd.subordinate {
for {
select {
case req := <-requests:
data := make(map[string]interface{})
data[subordinate.MessageKey] = "access"
data["remote-address"] = req.RemoteAddr
data["method"] = req.Method
data["path"] = req.Path
jsonData, err := json.Marshal(data)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(jsonData))
}
}
} else {
mdl := newAccessModel(shrToken, endpointUrl.String())
logrus.SetOutput(mdl)
@ -253,21 +325,56 @@ func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
}
close(requests)
cmd.destroy(accessResp.Payload.FrontendToken, env.Environment().ZitiIdentity, shrToken, zrok, auth)
cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
}
}
func (cmd *accessPrivateCommand) destroy(frontendName, envZId, shrToken string, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) {
logrus.Debugf("shutting down '%v'", shrToken)
req := share.NewUnaccessParams()
req.Body = &rest_model_zrok.UnaccessRequest{
FrontendToken: frontendName,
ShrToken: shrToken,
EnvZID: envZId,
func (cmd *accessPrivateCommand) error(err error) {
if cmd.subordinate {
subordinateError(err)
}
if !panicInstead {
tui.Error("unable to create private access", err)
}
panic(err)
}
func (cmd *accessPrivateCommand) shutdown(frontendToken, envZId, shrToken string, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) {
logrus.Infof("shutting down '%v'", shrToken)
req := share.NewUnaccessParams()
req.Body.FrontendToken = frontendToken
req.Body.ShareToken = shrToken
req.Body.EnvZID = envZId
if _, err := zrok.Share.Unaccess(req, auth); err == nil {
logrus.Debugf("shutdown complete")
} else {
logrus.Errorf("error shutting down: %v", err)
}
}
func (cmd *accessPrivateCommand) accessAgent(args []string, root env_core.Root) {
client, conn, err := agentClient.NewClient(root)
if err != nil {
tui.Error("error connecting to agent", err)
}
defer func() { _ = conn.Close() }()
req := &agentGrpc.AccessPrivateRequest{
Token: args[0],
BindAddress: cmd.bindAddress,
ResponseHeaders: cmd.responseHeaders,
}
if cmd.autoMode {
req.AutoMode = true
req.AutoAddress = cmd.autoAddress
req.AutoStartPort = uint32(cmd.autoStartPort)
req.AutoEndPort = uint32(cmd.autoEndPort)
}
acc, err := client.AccessPrivate(context.Background(), req)
if err != nil {
tui.Error("error creating access", err)
}
fmt.Println(acc)
}

View File

@ -46,5 +46,5 @@ func (cmd *adminCreateAccount) run(_ *cobra.Command, args []string) {
panic(err)
}
fmt.Println(resp.GetPayload().Token)
fmt.Println(resp.GetPayload().AccountToken)
}

View File

@ -3,7 +3,6 @@ package main
import (
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/rest_client_zrok/admin"
"github.com/openziti/zrok/rest_model_zrok"
"github.com/openziti/zrok/sdk/golang/sdk"
"github.com/openziti/zrok/tui"
"github.com/sirupsen/logrus"
@ -52,12 +51,10 @@ func (cmd *adminCreateFrontendCommand) run(_ *cobra.Command, args []string) {
permissionMode = sdk.ClosedPermissionMode
}
req := admin.NewCreateFrontendParams()
req.Body = &rest_model_zrok.CreateFrontendRequest{
ZID: zId,
PublicName: publicName,
URLTemplate: urlTemplate,
PermissionMode: string(permissionMode),
}
req.Body.ZID = zId
req.Body.PublicName = publicName
req.Body.URLTemplate = urlTemplate
req.Body.PermissionMode = string(permissionMode)
resp, err := zrok.Admin.CreateFrontend(req, mustGetAdminAuth())
if err != nil {
@ -71,5 +68,5 @@ func (cmd *adminCreateFrontendCommand) run(_ *cobra.Command, args []string) {
}
}
logrus.Infof("created global public frontend '%v'", resp.Payload.Token)
logrus.Infof("created global public frontend '%v'", resp.Payload.FrontendToken)
}

View File

@ -41,7 +41,7 @@ func (cmd *adminCreateOrgMemberCommand) run(_ *cobra.Command, args []string) {
}
req := admin.NewAddOrganizationMemberParams()
req.Body.Token = args[0]
req.Body.OrganizationToken = args[0]
req.Body.Email = args[1]
req.Body.Admin = cmd.admin

View File

@ -48,5 +48,5 @@ func (cmd *adminCreateOrganizationCommand) run(_ *cobra.Command, _ []string) {
panic(err)
}
logrus.Infof("created new organization with token '%v'", resp.Payload.Token)
logrus.Infof("created new organization with organization token '%v'", resp.Payload.OrganizationToken)
}

View File

@ -3,7 +3,6 @@ package main
import (
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/rest_client_zrok/admin"
"github.com/openziti/zrok/rest_model_zrok"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@ -41,7 +40,7 @@ func (cmd *adminDeleteFrontendCommand) run(_ *cobra.Command, args []string) {
}
req := admin.NewDeleteFrontendParams()
req.Body = &rest_model_zrok.DeleteFrontendRequest{FrontendToken: feToken}
req.Body.FrontendToken = feToken
_, err = zrok.Admin.DeleteFrontend(req, mustGetAdminAuth())
if err != nil {

View File

@ -39,7 +39,7 @@ func (cmd *adminDeleteOrgMemberCommand) run(_ *cobra.Command, args []string) {
}
req := admin.NewRemoveOrganizationMemberParams()
req.Body.Token = args[0]
req.Body.OrganizationToken = args[0]
req.Body.Email = args[1]
_, err = zrok.Admin.RemoveOrganizationMember(req, mustGetAdminAuth())

View File

@ -39,7 +39,7 @@ func (cmd *adminDeleteOrganizationCommand) run(_ *cobra.Command, args []string)
}
req := admin.NewDeleteOrganizationParams()
req.Body.Token = args[0]
req.Body.OrganizationToken = args[0]
_, err = zrok.Admin.DeleteOrganization(req, mustGetAdminAuth())
if err != nil {

View File

@ -5,7 +5,6 @@ import (
"github.com/jaevor/go-nanoid"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/rest_client_zrok/admin"
"github.com/openziti/zrok/rest_model_zrok"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@ -54,9 +53,8 @@ func (cmd *adminGenerateCommand) run(_ *cobra.Command, args []string) {
panic(err)
}
req := admin.NewInviteTokenGenerateParams()
req.Body = &rest_model_zrok.InviteTokenGenerateRequest{
Tokens: tokens,
}
req.Body.InviteTokens = tokens
_, err = zrok.Admin.InviteTokenGenerate(req, mustGetAdminAuth())
if err != nil {
if !panicInstead {

View File

@ -54,7 +54,7 @@ func (cmd *adminListFrontendsCommand) run(_ *cobra.Command, _ []string) {
t.AppendHeader(table.Row{"Token", "zId", "Public Name", "Url Template", "Created At", "Updated At"})
for _, pfe := range resp.Payload {
t.AppendRow(table.Row{
pfe.Token,
pfe.FrontendToken,
pfe.ZID,
pfe.PublicName,
pfe.URLTemplate,

View File

@ -41,7 +41,7 @@ func (cmd *adminListOrgMembersCommand) run(_ *cobra.Command, args []string) {
}
req := admin.NewListOrganizationMembersParams()
req.Body.Token = args[0]
req.Body.OrganizationToken = args[0]
resp, err := zrok.Admin.ListOrganizationMembers(req, mustGetAdminAuth())
if err != nil {

View File

@ -52,7 +52,7 @@ func (c *adminListOrganizationsCommand) run(_ *cobra.Command, _ []string) {
t.SetStyle(table.StyleColoredDark)
t.AppendHeader(table.Row{"Organization Token", "Description"})
for _, org := range resp.Payload.Organizations {
t.AppendRow(table.Row{org.Token, org.Description})
t.AppendRow(table.Row{org.OrganizationToken, org.Description})
}
t.Render()
fmt.Println()

View File

@ -33,7 +33,12 @@ func (cmd *adminMigrate) run(_ *cobra.Command, args []string) {
if err != nil {
panic(err)
}
logrus.Info(cf.Dump(inCfg, cf.DefaultOptions()))
// override the 'disable_auto_migration' setting... the user is requesting a migration here.
inCfg.Store.DisableAutoMigration = false
if _, err := store.Open(inCfg.Store); err != nil {
panic(err)
}

View File

@ -3,7 +3,6 @@ package main
import (
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/rest_client_zrok/admin"
"github.com/openziti/zrok/rest_model_zrok"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@ -49,11 +48,9 @@ func (cmd *adminUpdateFrontendCommand) run(_ *cobra.Command, args []string) {
}
req := admin.NewUpdateFrontendParams()
req.Body = &rest_model_zrok.UpdateFrontendRequest{
FrontendToken: feToken,
PublicName: cmd.newPublicName,
URLTemplate: cmd.newUrlTemplate,
}
req.Body.FrontendToken = feToken
req.Body.PublicName = cmd.newPublicName
req.Body.URLTemplate = cmd.newUrlTemplate
_, err = zrok.Admin.UpdateFrontend(req, mustGetAdminAuth())
if err != nil {

52
cmd/zrok/agentConsole.go Normal file
View File

@ -0,0 +1,52 @@
package main
import (
"context"
"fmt"
"github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/tui"
"github.com/spf13/cobra"
)
func init() {
agentCmd.AddCommand(newAgentConsoleCommand().cmd)
}
type agentConsoleCommand struct {
cmd *cobra.Command
}
func newAgentConsoleCommand() *agentConsoleCommand {
cmd := &cobra.Command{
Use: "console",
Short: "Open the Agent console",
Args: cobra.NoArgs,
}
command := &agentConsoleCommand{cmd}
cmd.Run = command.run
return command
}
func (cmd *agentConsoleCommand) run(_ *cobra.Command, _ []string) {
root, err := environment.LoadRoot()
if err != nil {
tui.Error("error loading zrokdir", err)
}
client, conn, err := agentClient.NewClient(root)
if err != nil {
tui.Error("error connecting to agent", err)
}
defer func() { _ = conn.Close() }()
v, err := client.Version(context.Background(), &agentGrpc.VersionRequest{})
if err != nil {
tui.Error("error getting agent version", err)
}
if err := openBrowser("http://" + v.ConsoleEndpoint); err != nil {
tui.Error(fmt.Sprintf("unable to open agent console at 'http://%v'", v.ConsoleEndpoint), err)
}
}

View File

@ -0,0 +1,55 @@
package main
import (
"context"
"fmt"
"github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/tui"
"github.com/spf13/cobra"
)
func init() {
agentReleaseCmd.AddCommand(newAgentReleaseAccessCommand().cmd)
}
type agentReleaseAccessCommand struct {
cmd *cobra.Command
}
func newAgentReleaseAccessCommand() *agentReleaseAccessCommand {
cmd := &cobra.Command{
Use: "access <frontendToken>",
Short: "Unbind an access from the zrok Agent",
Args: cobra.ExactArgs(1),
}
command := &agentReleaseAccessCommand{cmd: cmd}
cmd.Run = command.run
return command
}
func (cmd *agentReleaseAccessCommand) run(_ *cobra.Command, args []string) {
root, err := environment.LoadRoot()
if err != nil {
if !panicInstead {
tui.Error("unable to load environment", err)
}
panic(err)
}
client, conn, err := agentClient.NewClient(root)
if err != nil {
tui.Error("error connecting to agent", err)
}
defer conn.Close()
_, err = client.ReleaseAccess(context.Background(), &agentGrpc.ReleaseAccessRequest{
FrontendToken: args[0],
})
if err != nil {
tui.Error("error releasing access", err)
}
fmt.Println("success.")
}

55
cmd/zrok/agentReleaseShare.go Executable file
View File

@ -0,0 +1,55 @@
package main
import (
"context"
"fmt"
"github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/tui"
"github.com/spf13/cobra"
)
func init() {
agentReleaseCmd.AddCommand(newAgentReleaseShareCommand().cmd)
}
type agentReleaseShareCommand struct {
cmd *cobra.Command
}
func newAgentReleaseShareCommand() *agentReleaseShareCommand {
cmd := &cobra.Command{
Use: "share <token>",
Short: "Release a share from the zrok Agent",
Args: cobra.ExactArgs(1),
}
command := &agentReleaseShareCommand{cmd: cmd}
cmd.Run = command.run
return command
}
func (cmd *agentReleaseShareCommand) run(_ *cobra.Command, args []string) {
root, err := environment.LoadRoot()
if err != nil {
if !panicInstead {
tui.Error("unable to load environment", err)
}
panic(err)
}
client, conn, err := agentClient.NewClient(root)
if err != nil {
tui.Error("error connecting to agent", err)
}
defer conn.Close()
_, err = client.ReleaseShare(context.Background(), &agentGrpc.ReleaseShareRequest{
Token: args[0],
})
if err != nil {
tui.Error("error releasing share", err)
}
fmt.Println("success.")
}

72
cmd/zrok/agentStart.go Normal file
View File

@ -0,0 +1,72 @@
package main
import (
"github.com/openziti/zrok/agent"
"github.com/openziti/zrok/environment"
"github.com/openziti/zrok/tui"
"github.com/spf13/cobra"
"os"
"os/signal"
"syscall"
)
func init() {
agentCmd.AddCommand(newAgentStartCommand().cmd)
}
type agentStartCommand struct {
cmd *cobra.Command
consoleAddress string
consoleStartPort uint16
consoleEndPort uint16
}
func newAgentStartCommand() *agentStartCommand {
cmd := &cobra.Command{
Use: "start",
Short: "Start a zrok agent",
Args: cobra.NoArgs,
}
command := &agentStartCommand{cmd: cmd}
cmd.Run = command.run
cmd.Flags().StringVar(&command.consoleAddress, "console-address", "127.0.0.1", "gRPC gateway address")
cmd.Flags().Uint16Var(&command.consoleStartPort, "console-start-port", 8888, "gRPC gateway starting port")
cmd.Flags().Uint16Var(&command.consoleEndPort, "console-end-port", 8988, "gRPC gateway ending port")
return command
}
func (cmd *agentStartCommand) run(_ *cobra.Command, _ []string) {
root, err := environment.LoadRoot()
if err != nil {
tui.Error("error loading zrokdir", err)
}
if !root.IsEnabled() {
tui.Error("unable to load environment; did you 'zrok enable'?", nil)
}
cfg := agent.DefaultConfig()
cfg.ConsoleAddress = cmd.consoleAddress
cfg.ConsoleStartPort = cmd.consoleStartPort
cfg.ConsoleEndPort = cmd.consoleEndPort
a, err := agent.NewAgent(cfg, root)
if err != nil {
tui.Error("error creating agent", err)
}
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
cmd.shutdown(a)
os.Exit(0)
}()
if err := a.Run(); err != nil {
tui.Error("agent aborted", err)
}
}
func (cmd *agentStartCommand) shutdown(a *agent.Agent) {
a.Shutdown()
}

Some files were not shown because too many files have changed in this diff Show More