Merge pull request #797 from openziti/agent_ui_1

Agent UI 1 (#221)
This commit is contained in:
Michael Quigley 2024-11-20 11:43:11 -05:00 committed by GitHub
commit 639510b98b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
83 changed files with 9351 additions and 633 deletions

View File

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

View File

@ -6,8 +6,12 @@ MAJOR RELEASE: zrok reaches version 1.0.0!
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", 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 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)
## v0.4.45 ## v0.4.45
FIX: Update indirect dependency `github.com/golang-jwt/jwt/v4` to version `v4.5.1` (https://github.com/openziti/zrok/issues/794) FIX: Update indirect dependency `github.com/golang-jwt/jwt/v4` to version `v4.5.1` (https://github.com/openziti/zrok/issues/794)

View File

@ -1,26 +1,23 @@
package agent package agent
import ( import (
"bytes"
"encoding/json"
"errors"
"github.com/michaelquigley/pfxlog" "github.com/michaelquigley/pfxlog"
"github.com/openziti/zrok/agent/proctree" "github.com/openziti/zrok/agent/proctree"
"github.com/sirupsen/logrus" "github.com/openziti/zrok/cmd/zrok/subordinate"
"strings"
) )
type access struct { type access struct {
frontendToken string frontendToken string
token string token string
bindAddress string bindAddress string
autoMode bool
autoAddress string
autoStartPort uint16
autoEndPort uint16
responseHeaders []string responseHeaders []string
process *proctree.Child process *proctree.Child
readBuffer bytes.Buffer sub *subordinate.MessageHandler
booted bool
bootComplete chan struct{}
bootErr error
agent *Agent agent *Agent
} }
@ -31,46 +28,3 @@ func (a *access) monitor() {
} }
a.agent.rmAccess <- a a.agent.rmAccess <- a
} }
func (a *access) tail(data []byte) {
defer func() {
if r := recover(); r != nil {
logrus.Errorf("recovering: %v", r)
}
}()
a.readBuffer.Write(data)
if line, err := a.readBuffer.ReadString('\n'); err == nil {
line = strings.Trim(line, "\n")
if !a.booted {
in := make(map[string]interface{})
if err := json.Unmarshal([]byte(line), &in); err == nil {
if v, found := in["frontend_token"]; found {
if str, ok := v.(string); ok {
a.frontendToken = str
}
}
if v, found := in["bind_address"]; found {
if str, ok := v.(string); ok {
a.bindAddress = str
}
}
a.booted = true
} else {
a.bootErr = errors.New(line)
}
close(a.bootComplete)
} else {
if strings.HasPrefix(line, "{") {
in := make(map[string]interface{})
if err := json.Unmarshal([]byte(line), &in); err == nil {
pfxlog.ChannelLogger(a.token).Info(in)
}
} else {
pfxlog.ChannelLogger(a.token).Info(strings.Trim(line, "\n"))
}
}
} else {
a.readBuffer.WriteString(line)
}
}

View File

@ -3,8 +3,10 @@ package agent
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/proctree" "github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/environment" "github.com/openziti/zrok/environment"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"os" "os"
@ -21,28 +23,71 @@ func (i *agentGrpcImpl) AccessPrivate(_ context.Context, req *agentGrpc.AccessPr
} }
accCmd := []string{os.Args[0], "access", "private", "--subordinate", "-b", req.BindAddress, req.Token} 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{ acc := &access{
token: req.Token, token: req.Token,
bindAddress: req.BindAddress, bindAddress: req.BindAddress,
autoMode: req.AutoMode,
autoAddress: req.AutoAddress,
autoStartPort: uint16(req.AutoStartPort),
autoEndPort: uint16(req.AutoEndPort),
responseHeaders: req.ResponseHeaders, responseHeaders: req.ResponseHeaders,
bootComplete: make(chan struct{}), sub: subordinate.NewMessageHandler(),
agent: i.agent, 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) logrus.Infof("executing '%v'", accCmd)
acc.process, err = proctree.StartChild(acc.tail, accCmd...) acc.process, err = proctree.StartChild(acc.sub.Tail, accCmd...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
go acc.monitor() <-acc.sub.BootComplete
<-acc.bootComplete
if acc.bootErr == nil { if bootErr == nil {
go acc.monitor()
i.agent.addAccess <- acc i.agent.addAccess <- acc
return &agentGrpc.AccessPrivateResponse{FrontendToken: acc.frontendToken}, nil return &agentGrpc.AccessPrivateResponse{FrontendToken: acc.frontendToken}, nil
}
return nil, acc.bootErr } 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)
}
} }

View File

@ -1,33 +1,42 @@
package agent package agent
import ( import (
"context"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/agentUi"
"github.com/openziti/zrok/agent/proctree" "github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/environment/env_core" "github.com/openziti/zrok/environment/env_core"
"github.com/openziti/zrok/sdk/golang/sdk" "github.com/openziti/zrok/sdk/golang/sdk"
"github.com/openziti/zrok/util"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"net" "net"
"net/http"
"os" "os"
) )
type Agent struct { type Agent struct {
root env_core.Root cfg *AgentConfig
agentSocket string httpEndpoint string
shares map[string]*share root env_core.Root
addShare chan *share agentSocket string
rmShare chan *share shares map[string]*share
accesses map[string]*access addShare chan *share
addAccess chan *access rmShare chan *share
rmAccess chan *access accesses map[string]*access
addAccess chan *access
rmAccess chan *access
} }
func NewAgent(root env_core.Root) (*Agent, error) { func NewAgent(cfg *AgentConfig, root env_core.Root) (*Agent, error) {
if !root.IsEnabled() { if !root.IsEnabled() {
return nil, errors.Errorf("unable to load environment; did you 'zrok enable'?") return nil, errors.Errorf("unable to load environment; did you 'zrok enable'?")
} }
return &Agent{ return &Agent{
cfg: cfg,
root: root, root: root,
shares: make(map[string]*share), shares: make(map[string]*share),
addShare: make(chan *share), addShare: make(chan *share),
@ -44,7 +53,6 @@ func (a *Agent) Run() error {
if err := proctree.Init("zrok Agent"); err != nil { if err := proctree.Init("zrok Agent"); err != nil {
return err return err
} }
go a.manager()
agentSocket, err := a.root.AgentSocket() agentSocket, err := a.root.AgentSocket()
if err != nil { if err != nil {
@ -56,6 +64,9 @@ func (a *Agent) Run() error {
} }
a.agentSocket = agentSocket a.agentSocket = agentSocket
go a.manager()
go a.gateway(a.cfg)
srv := grpc.NewServer() srv := grpc.NewServer()
agentGrpc.RegisterAgentServer(srv, &agentGrpcImpl{agent: a}) agentGrpc.RegisterAgentServer(srv, &agentGrpcImpl{agent: a})
if err := srv.Serve(l); err != nil { if err := srv.Serve(l); err != nil {
@ -81,6 +92,36 @@ func (a *Agent) Shutdown() {
} }
} }
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() { func (a *Agent) manager() {
logrus.Info("started") logrus.Info("started")
defer logrus.Warn("exited") defer logrus.Warn("exited")

View File

@ -7,6 +7,7 @@
package agentGrpc package agentGrpc
import ( import (
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect" reflect "reflect"
@ -145,7 +146,11 @@ type AccessPrivateRequest struct {
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"` Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
BindAddress string `protobuf:"bytes,2,opt,name=bindAddress,proto3" json:"bindAddress,omitempty"` BindAddress string `protobuf:"bytes,2,opt,name=bindAddress,proto3" json:"bindAddress,omitempty"`
ResponseHeaders []string `protobuf:"bytes,3,rep,name=responseHeaders,proto3" json:"responseHeaders,omitempty"` AutoMode bool `protobuf:"varint,3,opt,name=autoMode,proto3" json:"autoMode,omitempty"`
AutoAddress string `protobuf:"bytes,4,opt,name=autoAddress,proto3" json:"autoAddress,omitempty"`
AutoStartPort uint32 `protobuf:"varint,5,opt,name=autoStartPort,proto3" json:"autoStartPort,omitempty"`
AutoEndPort uint32 `protobuf:"varint,6,opt,name=autoEndPort,proto3" json:"autoEndPort,omitempty"`
ResponseHeaders []string `protobuf:"bytes,7,rep,name=responseHeaders,proto3" json:"responseHeaders,omitempty"`
} }
func (x *AccessPrivateRequest) Reset() { func (x *AccessPrivateRequest) Reset() {
@ -194,6 +199,34 @@ func (x *AccessPrivateRequest) GetBindAddress() string {
return "" return ""
} }
func (x *AccessPrivateRequest) GetAutoMode() bool {
if x != nil {
return x.AutoMode
}
return false
}
func (x *AccessPrivateRequest) GetAutoAddress() string {
if x != nil {
return x.AutoAddress
}
return ""
}
func (x *AccessPrivateRequest) GetAutoStartPort() uint32 {
if x != nil {
return x.AutoStartPort
}
return 0
}
func (x *AccessPrivateRequest) GetAutoEndPort() uint32 {
if x != nil {
return x.AutoEndPort
}
return 0
}
func (x *AccessPrivateRequest) GetResponseHeaders() []string { func (x *AccessPrivateRequest) GetResponseHeaders() []string {
if x != nil { if x != nil {
return x.ResponseHeaders return x.ResponseHeaders
@ -1052,7 +1085,8 @@ type VersionResponse struct {
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
V string `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"` V string `protobuf:"bytes,1,opt,name=v,proto3" json:"v,omitempty"`
ConsoleEndpoint string `protobuf:"bytes,2,opt,name=consoleEndpoint,proto3" json:"consoleEndpoint,omitempty"`
} }
func (x *VersionResponse) Reset() { func (x *VersionResponse) Reset() {
@ -1094,165 +1128,198 @@ func (x *VersionResponse) GetV() string {
return "" return ""
} }
func (x *VersionResponse) GetConsoleEndpoint() string {
if x != nil {
return x.ConsoleEndpoint
}
return ""
}
var File_agent_agentGrpc_agent_proto protoreflect.FileDescriptor var File_agent_agentGrpc_agent_proto protoreflect.FileDescriptor
var file_agent_agentGrpc_agent_proto_rawDesc = []byte{ var file_agent_agentGrpc_agent_proto_rawDesc = []byte{
0x0a, 0x1b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x47, 0x72, 0x70, 0x0a, 0x1b, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x47, 0x72, 0x70,
0x63, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96, 0x01, 0x63, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67,
0x0a, 0x0c, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x24, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61,
0x0a, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x96, 0x01, 0x0a, 0x0c,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x24, 0x0a, 0x0d,
0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x69, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b,
0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
0x0b, 0x62, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x69, 0x6e, 0x64,
0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62,
0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65,
0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3d, 0x0a, 0x15, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20,
0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61,
0x24, 0x0a, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3d, 0x0a, 0x15, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x78, 0x0a, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01,
0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f,
0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xfe, 0x01, 0x0a, 0x14, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72,
0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05,
0x73, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b,
0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x69, 0x6e, 0x64, 0x41, 0x64, 0x64,
0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x22, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x4d, 0x6f, 0x64, 0x65,
0x3c, 0x0a, 0x14, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x75, 0x74, 0x6f, 0x4d, 0x6f, 0x64, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x41, 0x64, 0x64, 0x72, 0x65,
0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x17, 0x0a, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50,
0x15, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x6f, 0x72, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x61, 0x75, 0x74, 0x6f, 0x53,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x0a, 0x13, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x74, 0x61, 0x72, 0x74, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x6f,
0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x45, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x61,
0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x75, 0x74, 0x6f, 0x45, 0x6e, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65,
0x6b, 0x65, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x68, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x73, 0x18, 0x07, 0x20,
0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x85, 0x02, 0x0a, 0x0b, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x65, 0x61,
0x53, 0x68, 0x61, 0x72, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x64, 0x65, 0x72, 0x73, 0x22, 0x3c, 0x0a, 0x14, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41,
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x0d,
0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20,
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x54, 0x6f, 0x6b,
0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x65, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63,
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x0a, 0x13, 0x52,
0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
0x10, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x16, 0x0a, 0x14, 0x52, 0x65, 0x6c, 0x65,
0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x61, 0x63, 0x22, 0x85, 0x02, 0x0a, 0x0b, 0x53, 0x68, 0x61, 0x72, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c,
0x6b, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x28, 0x09, 0x52, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d,
0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x18, 0x07, 0x20, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65,
0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d,
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65,
0x74, 0x75, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x13, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x69, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76,
0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76,
0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45, 0x6e,
0x67, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x66, 0x72,
0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x28,
0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x0a, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64,
0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x6f, 0x73,
0x08, 0x52, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64,
0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09,
0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x2c, 0x0a, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x13, 0x53, 0x68, 0x61,
0x14, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x86, 0x03, 0x0a, 0x12, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b,
0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62,
0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e,
0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e,
0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x62, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64,
0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x22,
0x74, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x05,
0x03, 0x28, 0x09, 0x52, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x6e,
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x2c, 0x0a, 0x14, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61,
0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f,
0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
0x63, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x22, 0x86, 0x03, 0x0a, 0x12, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
0x63, 0x75, 0x72, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65,
0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6f, 0x61, 0x75, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12,
0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x3c, 0x0a, 0x19, 0x6f, 0x61, 0x1c, 0x0a, 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x18, 0x02, 0x20, 0x03,
0x75, 0x74, 0x68, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x28, 0x09, 0x52, 0x09, 0x62, 0x61, 0x73, 0x69, 0x63, 0x41, 0x75, 0x74, 0x68, 0x12, 0x2c, 0x0a,
0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6f, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69,
0x61, 0x75, 0x74, 0x68, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65,
0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x73, 0x12, 0x2e, 0x0a, 0x12, 0x6f, 0x61, 0x75, 0x74, 0x6e, 0x64, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62,
0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x08, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x0a,
0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x6f, 0x61, 0x75,
0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47, 0x72, 0x52, 0x0d, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12,
0x61, 0x6e, 0x74, 0x73, 0x22, 0x59, 0x0a, 0x13, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x75, 0x62, 0x3c, 0x0a, 0x19, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64,
0x6c, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x72, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x03,
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x28, 0x09, 0x52, 0x19, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64,
0x6e, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x50, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x73, 0x12, 0x2e, 0x0a,
0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x66, 0x72, 0x12, 0x6f, 0x61, 0x75, 0x74, 0x68, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72,
0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x76, 0x61, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6f, 0x61, 0x75, 0x74, 0x68,
0x74, 0x0a, 0x14, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x16, 0x0a,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x06, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x63,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2a, 0x0a, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x47,
0x10, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x63, 0x63,
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x73, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x22, 0x59, 0x0a, 0x13, 0x53, 0x68, 0x61,
0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x72, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x65, 0x63, 0x75, 0x72, 0x65, 0x22, 0xb3, 0x01, 0x0a, 0x15, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65,
0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x09, 0x52, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f,
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x74, 0x73, 0x22, 0x74, 0x0a, 0x14, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73,
0x4d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05,
0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b,
0x4d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65, 0x6e, 0x12, 0x2a, 0x0a, 0x10, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x45, 0x6e,
0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x6f, 0x76,
0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x1a,
0x52, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08,
0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x05, 0x20, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x22, 0xb3, 0x01, 0x0a, 0x15, 0x53,
0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70,
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x61, 0x0a, 0x0e, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x62, 0x61,
0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x32, 0x0d, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09,
0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x2c, 0x0a, 0x11, 0x66, 0x72,
0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x06, 0x73, 0x68, 0x61, 0x72, 0x65, 0x73, 0x22, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18,
0x10, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x45,
0x74, 0x22, 0x1f, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, 0x72, 0x67,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x76, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x65, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
0x01, 0x76, 0x32, 0xe4, 0x03, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x40, 0x0a, 0x0d, 0x22, 0x0f, 0x0a, 0x0d, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x74, 0x22, 0x61, 0x0a, 0x0e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x69, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x44, 0x65,
0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x40, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x08, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x24,
0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x0a, 0x06, 0x73, 0x68, 0x61, 0x72, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c,
0x15, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x06, 0x73, 0x68,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x61, 0x72, 0x65, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52,
0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x49, 0x0a, 0x0f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x12, 0x3d, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x76, 0x18, 0x01,
0x12, 0x14, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x20, 0x01, 0x28, 0x09, 0x52, 0x01, 0x76, 0x12, 0x28, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x73, 0x6f,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x6c, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, 0x0f, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e,
0x40, 0x0a, 0x0d, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x74, 0x32, 0xac, 0x05, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x5f, 0x0a, 0x0d, 0x41,
0x12, 0x15, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x15, 0x2e, 0x41,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x69, 0x76,
0x00, 0x12, 0x3d, 0x0a, 0x0c, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4,
0x65, 0x12, 0x14, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x93, 0x02, 0x19, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x63, 0x63, 0x65, 0x73, 0x73, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x5f, 0x0a, 0x0d,
0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x15, 0x2e,
0x12, 0x3a, 0x0a, 0x0b, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71,
0x13, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3,
0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x06, 0xe4, 0x93, 0x02, 0x19, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f,
0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x5b, 0x0a,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x14, 0x2e,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2e, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x72, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x02, 0x18, 0x22, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x72, 0x65,
0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x7a, 0x69, 0x74, 0x69, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x12, 0x40, 0x0a, 0x0d, 0x53, 0x68,
0x2f, 0x7a, 0x72, 0x6f, 0x6b, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x12, 0x15, 0x2e, 0x53, 0x68,
0x74, 0x47, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x52, 0x65, 0x73, 0x65, 0x72, 0x76,
0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5b, 0x0a, 0x0c,
0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x14, 0x2e, 0x53,
0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x15, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74,
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x18, 0x22, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x68, 0x61,
0x72, 0x65, 0x50, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x57, 0x0a, 0x0b, 0x53, 0x68, 0x61,
0x72, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x12, 0x13, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65,
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e,
0x53, 0x68, 0x61, 0x72, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x22, 0x15, 0x2f, 0x76, 0x31,
0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x73, 0x68, 0x61, 0x72, 0x65, 0x50, 0x75, 0x62, 0x6c,
0x69, 0x63, 0x12, 0x43, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x2e, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, 0x2e, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82,
0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74,
0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x47, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x0f, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x10, 0x2e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f,
0x76, 0x31, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f,
0x70, 0x65, 0x6e, 0x7a, 0x69, 0x74, 0x69, 0x2f, 0x7a, 0x72, 0x6f, 0x6b, 0x2f, 0x61, 0x67, 0x65,
0x6e, 0x74, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x47, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

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
)

View File

@ -2,15 +2,45 @@ syntax = "proto3";
option go_package = "github.com/openziti/zrok/agent/agentGrpc"; option go_package = "github.com/openziti/zrok/agent/agentGrpc";
import "google/api/annotations.proto";
service Agent { service Agent {
rpc AccessPrivate(AccessPrivateRequest) returns (AccessPrivateResponse) {} rpc AccessPrivate(AccessPrivateRequest) returns (AccessPrivateResponse) {
rpc ReleaseAccess(ReleaseAccessRequest) returns (ReleaseAccessResponse) {} option(google.api.http) = {
rpc ReleaseShare(ReleaseShareRequest) returns (ReleaseShareResponse) {} 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 ShareReserved(ShareReservedRequest) returns (ShareReservedResponse) {}
rpc SharePrivate(SharePrivateRequest) returns (SharePrivateResponse) {} rpc SharePrivate(SharePrivateRequest) returns (SharePrivateResponse) {
rpc SharePublic(SharePublicRequest) returns (SharePublicResponse) {} option(google.api.http) = {
rpc Status(StatusRequest) returns (StatusResponse) {} post: "/v1/agent/sharePrivate"
rpc Version(VersionRequest) returns (VersionResponse) {} };
}
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 { message AccessDetail {
@ -27,7 +57,11 @@ message AccessPrivateResponse{
message AccessPrivateRequest{ message AccessPrivateRequest{
string token = 1; string token = 1;
string bindAddress = 2; string bindAddress = 2;
repeated string responseHeaders = 3; bool autoMode = 3;
string autoAddress = 4;
uint32 autoStartPort = 5;
uint32 autoEndPort = 6;
repeated string responseHeaders = 7;
} }
message ReleaseAccessRequest { message ReleaseAccessRequest {
@ -112,4 +146,5 @@ message VersionRequest {
message VersionResponse { message VersionResponse {
string v = 1; 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"
}
}
}
}
}
}

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 },
],
},
},
)

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

@ -0,0 +1,103 @@
<!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>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<div id="footer">
<a rel="noopener noreferrer" href="https://zrok.io">
<svg width="150" height="45" viewBox="0 0 100 30" xml:space="preserve" style="clip-rule:evenodd;fill-rule:evenodd;stroke-miterlimit:10" id="svg48" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<defs id="defs48" /><namedview id="namedview48" pagecolor="#ffffff" bordercolor="#000000" borderopacity="0.25"/>
<g transform="matrix(0.0639619,0,0,0.0388212,-1.65041,-1.44321)" id="g1">
<path d="m 1589.31,230.468 c 0,-106.573 -52.51,-193.096 -117.2,-193.096 H 143.033 c -64.683,0 -117.198,86.523 -117.198,193.096 v 386.191 c 0,106.573 52.515,193.096 117.198,193.096 H 1472.11 c 64.69,0 117.2,-86.523 117.2,-193.096 z" style="fill:#170549" id="path1" />
</g>
<g transform="matrix(-0.0296355,-0.233707,-0.233707,0.0296355,76.730746,23.501948)" id="g15">
<path d="m -30.685,-47.339 c 0.924,3.31 1.524,5.653 1.574,6.05 0.401,2.368 -0.97,54.354 -1.574,56.749 -0.171,1.029 -1.342,5.311 -2.995,10.56 -11.859,-21.982 -11.292,-51.69 2.995,-73.359" style="fill:#a3a3a3" id="path14" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,89.174746,26.961548)" id="g23">
<path d="m 0,-51.2 19.7,-3 c 5.6,-0.9 10.9,2.8 11.9,8.4 l 2.7,17.7 C 29.9,-18.1 23.6,-9 16,-1.3 10.9,3.9 15.9,-1.6 10,2.1 L 1,-39.8 C 0.1,-45.3 -5.7,-50.3 0,-51.2" style="fill:#b3b3b3" id="path22" />
</g>
<g transform="matrix(-0.160445,0.172496,0.172496,0.160445,96.828546,10.865078)" id="g24">
<path d="m 61.55,-141.309 c -46.795,1.269 -84.666,39.929 -84.684,86.346 -0.018,46.417 37.889,83.042 84.684,81.772 46.795,-1.269 84.666,-39.929 84.684,-86.346 0.018,-46.417 -37.889,-83.042 -84.684,-81.772" id="path23" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,56.099446,11.884458)" id="g25">
<path d="M 0,34.1 8.7,32.5 C 4.8,21.8 3.2,10.4 4,-0.9 V -1.1 L -6.1,0.7 c -5.4,0.9 -9.2,6.1 -8.3,11.6 l 2.5,13.8 c 1.1,5.5 6.5,9.1 11.9,8" style="fill:#ffffff" id="path24" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,99.257546,5.2882484)" id="g26">
<path d="m 0,33.4 -8.8,1.1 C -8.3,23.1 -10.2,11.8 -14.4,1.2 V 1 L -4.2,-0.3 C 1.3,-1.1 6.4,2.8 7.2,8.3 L 9,22.2 C 9.5,27.8 5.5,32.8 0,33.4" style="fill:#ffffff" id="path25" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,76.712646,31.343248)" id="g27">
<path d="m 0,-161.7 c -22,0.5 -42.9,9.5 -58.3,25.2 -15.3,15.3 -23.7,36.2 -23.3,57.8 0.4,21.5 9.6,42 25.5,56.5 C -40,-7.3 -18.7,0.7 3.2,0 25.2,-0.5 46.1,-9.5 61.5,-25.2 76.7,-40.6 85.1,-61.4 84.8,-83 84.4,-104.5 75.2,-125 59.4,-139.6 43.2,-154.4 21.9,-162.4 0,-161.7 m -61.7,22.1 c 16.3,-16.6 38.4,-26.2 61.6,-26.8 23.2,-0.7 45.7,7.7 62.7,23.4 16.8,15.4 26.5,37 26.9,59.8 C 89.9,-60.3 81,-38.3 64.9,-22 48.6,-5.4 26.5,4.1 3.3,4.7 -19.8,5.4 -42.3,-3 -59.3,-18.7 c -16.8,-15.4 -26.5,-37.1 -26.9,-59.8 -0.5,-22.9 8.4,-44.9 24.5,-61.1" style="fill-rule:nonzero" id="path26" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,56.099446,11.790228)" id="g28">
<path d="M 0,34.5 8.7,32.9 C 4.8,22.2 3.2,10.8 4,-0.5 v -0.2 l -7.7,1.4 c 0.1,9.2 0.2,17.8 2.8,27.3 l -8.8,1.6 c -0.4,0 -0.7,0.3 -0.8,0.7 2.5,3.2 6.5,4.9 10.5,4.2" style="fill:#a3a3a3" id="path27" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,99.257546,5.5473884)" id="g29">
<path d="m 0,32.3 -8.8,1.1 C -8.3,22 -10.2,10.7 -14.4,0.1 v -0.2 l 7.7,-1 c 2.7,8.8 5.2,17 5.6,26.8 L 7.7,24.6 C 8.1,24.5 8.5,24.7 8.7,25 7.4,29 4,31.8 0,32.3" style="fill:#a3a3a3" id="path28" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,57.418746,12.449848)" id="g30">
<path d="m 0,28.3 -6,1.1 c -2,0.4 -4.2,-0.1 -5.9,-1.2 -1.7,-1.1 -2.9,-2.9 -3.3,-4.9 L -17.6,9.5 c -0.4,-2 0.1,-4.1 1.3,-5.7 1.2,-1.7 3,-2.8 5.1,-3.2 L -4,-0.7 c -0.4,9.8 1,19.6 4,29 M -5.2,34 3.6,32.4 6.4,31.9 5.5,29.3 C 1.7,18.9 0.1,7.9 0.9,-3.2 V -3.5 L 0.8,-4 0.4,-6.3 -2,-5.9 -12.1,-4.1 c -3.3,0.6 -6.2,2.4 -8.2,5.1 -1.9,2.7 -2.7,6 -2.1,9.2 l 2.5,13.8 c 0.6,3.2 2.5,6.1 5.2,7.9 2.9,2 6.2,2.7 9.5,2.1" style="fill-rule:nonzero" id="path29" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,97.749846,5.8536384)" id="g31">
<path d="m 0,29.5 6.1,-0.8 c 2.1,-0.3 3.9,-1.3 5.2,-3 1.3,-1.6 1.9,-3.6 1.6,-5.7 L 11.1,6.1 C 10.8,4.1 9.8,2.2 8.1,1 6.4,-0.2 4.4,-0.8 2.3,-0.5 L -5,0.4 c 1.7,4.6 2.9,9.4 3.7,14.2 0.9,5.1 1.3,10 1.3,14.9 m 6.6,3.8 -8.8,1.1 -2.8,0.4 0.1,-2.7 C -4.4,21.1 -6.3,10 -10.4,-0.2 l -0.1,-0.3 -0.1,-0.5 -0.3,-2.3 2.4,-0.3 10.2,-1.3 c 3.3,-0.4 6.7,0.4 9.3,2.4 2.6,2 4.4,4.9 4.8,8.1 l 1.8,13.9 c 0.4,3.3 -0.5,6.6 -2.6,9.1 -2,2.6 -5,4.3 -8.4,4.7" style="fill-rule:nonzero" id="path30" />
</g>
<g transform="matrix(-0.094487,-0.2158,-0.2158,0.094487,60.008346,10.163168)" id="g32">
<path d="m -68.968,-142.292 c -20.852,8.475 -37.24,25.148 -45.56,46.039 -17.44,43.442 2.976,93.561 45.56,112.032 9.157,3.96 18.932,6.339 28.941,6.76 -61.01,-17.172 -106.83,-100.38 -28.941,-164.831" style="fill:#ffffff" id="path31" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,95.346946,21.496048)" id="g33">
<path d="m 0,-10.4 c 1.7,-4.2 3,-8.6 3.9,-13 -7.8,18.2 -18.4,31.7 -30.5,41.1 -11,8.6 -23.9,14.3 -37.7,16.6 -13.2,2.2 -26.8,1.5 -39.8,-2 -13.1,-3.4 -25.4,-9.4 -36.2,-17.6 1.5,1.7 3.2,3.4 4.9,5 16.1,14.9 37.4,22.8 59.3,22.1 22,-0.5 42.9,-9.5 58.3,-25.2 C -10,9 -4,-0.2 0,-10.4 m 10.4,-31.7 c 0.3,11.4 -1.7,22.7 -5.9,33.3 -4.3,10.7 -10.6,20.4 -18.7,28.5 -16.3,16.6 -38.4,26.1 -61.6,26.7 -23.1,0.7 -45.6,-7.7 -62.6,-23.4 -3.8,-3.5 -7.3,-7.3 -10.4,-11.4 -3.1,-4.1 -5.7,-8.4 -8,-13 l -5.1,-13.9 9.1,11.4 c 13,15.5 30.6,26.6 50.2,31.7 12.3,3.3 25.1,4 37.7,1.9 12.9,-2.1 25.1,-7.5 35.5,-15.6 15.1,-11.8 27.6,-30.2 35.2,-56.7 l 2.7,-14.9 z" style="fill-rule:nonzero" id="path32" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,62.507246,12.284948)" id="g34">
<path d="m 0,-59 c 32.8,-33.4 87,-34.8 121,-3.2 16.1,14.8 25.6,35.6 26.2,57.4 -12.8,-31.9 -30.4,-46.9 -51.7,-54.1 -33.2,-11.2 -64.8,-8.3 -93,24.3 -20.7,23.7 -19.6,48.4 -18,69.4 C -30.5,4.5 -25.5,-33.1 0,-59" style="fill:#ffffff" id="path33" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,76.665546,22.037948)" id="g35">
<path d="m 0,-124.1 c -22,0.5 -42.9,9.5 -58.3,25.2 -11.7,11.8 -19.5,27 -22.2,43.4 -1.9,11.4 -1.3,23 1.8,34.1 -0.1,-6.4 0.4,-12.9 1.4,-19.2 2.4,-13.7 8.5,-26.5 17.8,-36.9 14.5,-16.7 29.9,-25.9 46,-29.4 16.1,-3.5 32.7,-1.4 49.7,4.4 11.3,3.7 21.6,10 30,18.4 6.7,6.8 12.3,14.6 16.7,23.1 C 81.7,-66.3 80,-71.5 77.7,-76.5 73.3,-86.1 67.1,-94.7 59.3,-101.9 43.1,-116.8 21.9,-124.8 0,-124.1 m -61.8,22.1 c 16.3,-16.6 38.4,-26.2 61.7,-26.8 23.1,-0.7 45.6,7.7 62.6,23.4 8.2,7.6 14.8,16.7 19.4,26.9 4.6,10.1 7.1,21.1 7.4,32.2 l -0.2,13.2 -4.3,-12.2 C 78.5,-61 71.1,-72.4 62.7,-80.8 54.8,-88.7 45.1,-94.6 34.5,-98.1 c -16.2,-5.5 -32,-7.5 -47.1,-4.2 -15.1,3.3 -29.5,11.9 -43.3,27.8 -8.7,9.8 -14.5,21.8 -16.7,34.6 -2.1,11.5 -1.4,22.8 -0.6,33.1 l 0.9,12.2 -5.4,-11.1 c -7.7,-15.7 -10.4,-33.4 -7.5,-50.7 2.8,-17.1 11,-33.2 23.4,-45.6" style="fill-rule:nonzero" id="path34" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,97.043046,0.69445839)" id="g36">
<path d="m 0,37.2 c 0.3,2.4 0.5,4.8 0.5,7.3 -12.8,-31.9 -30.4,-46.9 -51.7,-54.1 -33.2,-11.2 -75.4,-3.5 -98,26.7 -6.8,9 -18.6,29.7 -15.7,54.2 -7.6,-24.3 -1.1,-48.6 20.4,-70.4 32.7,-33.5 86.8,-35 120.8,-3.3 C -12.1,8.2 -3.9,22 0,37.2" style="fill:#e6e6e6" id="path35" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,92.166646,14.028248)" id="g37">
<path d="m 0,-49.8 c 6.3,6.4 11.6,13.6 15.8,21.4 -1.6,-4 -3.5,-7.9 -5.7,-11.5 -3.9,-6.6 -8.8,-12.5 -14.4,-17.8 -16.2,-14.9 -37.5,-22.9 -59.5,-22.3 -22.2,0.6 -43.2,9.7 -58.7,25.5 -10.4,10.6 -17.2,21.7 -20.5,33.2 -1.4,4.9 -2.2,9.9 -2.3,15 0.5,-2.5 1,-4.8 1.7,-7.1 2.9,-9.8 7.5,-19.1 13.5,-27.3 11.1,-14.9 26.7,-24.4 43.8,-29.1 18.6,-5 38.2,-4.4 56.4,1.7 11.3,3.7 21.5,10 29.9,18.3 m 22.6,30.1 c 0.2,1.3 0.3,2.6 0.4,3.7 0.1,1.2 0.1,2.5 0.2,3.7 l 0.3,10.9 -4.1,-10.2 C 13.1,-27.3 5.6,-38.8 -2.8,-47.3 c -7.9,-7.9 -17.7,-13.9 -28.3,-17.4 -17.5,-5.8 -36.3,-6.4 -54.1,-1.6 -16.3,4.4 -31.2,13.5 -41.7,27.6 -5.8,7.9 -10.2,16.7 -13,26.1 -2.6,8.7 -3.4,17.8 -2.4,26.8 l 2.4,20.4 -6.2,-19.4 c -4,-12.2 -4.2,-25.2 -0.7,-37.5 3.5,-12 10.5,-23.7 21.4,-34.7 l 0.1,-0.1 c 16.2,-16.5 38.3,-26 61.4,-26.6 23,-0.7 45.3,7.6 62.2,23.2 l 0.1,0.1 c 5.9,5.4 10.9,11.7 15.1,18.6 4.1,6.8 7.2,14.2 9.1,21.9 z" style="fill-rule:nonzero" id="path36" />
</g>
<g transform="matrix(0.131129,0.19571,0.19571,-0.131129,60.042246,4.7938284)" id="g38">
<path d="m 32.805,-16.969 c 0,0 -31.438,29.611 -14.637,74.808 1.315,4.657 15.792,4.346 14.637,-2.946 -1.154,-7.292 -9.456,-35.313 13.492,-66.457 1.659,-2.195 -8.429,-10.963 -13.492,-5.405" style="fill:#e6e6e6" id="path37" />
</g>
<g transform="matrix(0.235579,0,0,0.235579,52.094646,-8.3046516)" id="g45">
<g opacity="0.25" id="g44">
<g transform="matrix(-1,0,0,1,141,101.8)" id="g39">
<path d="m 0,-36.8 c -10.162,0 -18.4,8.238 -18.4,18.4 C -18.4,-8.238 -10.162,0 0,0 10.162,0 18.4,-8.238 18.4,-18.4 18.4,-28.562 10.162,-36.8 0,-36.8" style="fill:#fefcf9;fill-rule:nonzero" id="path38" />
</g>
<g transform="matrix(-1,0,0,1,143.3,88.2)" id="g40">
<path d="m 0,-14.2 c -3.921,0 -7.1,3.179 -7.1,7.1 0,3.921 3.179,7.1 7.1,7.1 3.921,0 7.1,-3.179 7.1,-7.1 0,-3.921 -3.179,-7.1 -7.1,-7.1" style="fill-rule:nonzero" id="path39" />
</g>
<g transform="matrix(-1,0,0,1,71.8,112.5)" id="g41">
<path d="m 0,-36.8 c -10.162,0 -18.4,8.238 -18.4,18.4 C -18.4,-8.238 -10.162,0 0,0 10.162,0 18.4,-8.238 18.4,-18.4 18.4,-28.562 10.162,-36.8 0,-36.8" style="fill:#fefcf9;fill-rule:nonzero" id="path40" />
</g>
<g transform="translate(116.1,122.6)" id="g42">
<path d="m 0,17.4 c -11.8,1.8 -23.8,-0.3 -34.3,-5.8 -0.9,-0.5 -1.3,-1.6 -0.8,-2.5 0.5,-0.9 1.6,-1.3 2.5,-0.8 20.1,10.8 44.9,7 60.7,-9.4 0.7,-0.7 1.9,-0.7 2.6,0 0.7,0.7 0.7,1.9 0,2.6 -7.9,8 -18,13.4 -29,15.6 -0.5,0 -1.1,0.2 -1.7,0.3 z" style="fill:none;fill-rule:nonzero;stroke:#ffffff;stroke-width:16.98px;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4" id="path41" />
</g>
<g transform="matrix(-1,0,0,1,76.2,97.8)" id="g43">
<path d="m 0,-14.2 c -3.921,0 -7.1,3.179 -7.1,7.1 0,3.921 3.179,7.1 7.1,7.1 3.921,0 7.1,-3.179 7.1,-7.1 0,-3.921 -3.179,-7.1 -7.1,-7.1" style="fill-rule:nonzero" id="path42" />
</g>
</g>
</g>
<g id="zrok" transform="matrix(0.02734414,0,0,0.02978162,2.3966205,5.6320267)">&#10; <path d="M 508.489,211.308 300.982,391.439 h 207.507 v 93.53 H 134.977 v -93.53 L 342.483,211.308 H 134.977 v -93.53 h 373.512 z" style="fill:#7bf600;fill-rule:nonzero" id="path45" />
<path d="m 791.453,218.236 c -31.692,0 -64.39,6.928 -98.094,20.784 V 484.969 H 561.309 V 117.778 h 116.958 l 7.546,45.033 C 729.075,128.17 774.349,110.85 821.636,110.85 h 33.955 v 107.386 z" style="fill:#7bf600;fill-rule:nonzero" id="path46" />
<path d="m 1300.79,381.047 c 0,34.64 -10.69,61.776 -32.07,81.405 -21.38,19.63 -50.93,29.445 -88.66,29.445 H 1006.5 c -37.723,0 -67.277,-9.815 -88.657,-29.445 -21.379,-19.629 -32.069,-46.765 -32.069,-81.405 V 221.7 c 0,-34.641 10.69,-61.776 32.069,-81.405 21.38,-19.63 50.934,-29.445 88.657,-29.445 h 173.56 c 37.73,0 67.28,9.815 88.66,29.445 21.38,19.629 32.07,46.764 32.07,81.405 z M 1168.74,232.092 c 0,-18.475 -10.06,-27.712 -30.18,-27.712 h -90.55 c -20.13,0 -30.19,9.237 -30.19,27.712 v 138.563 c 0,18.475 10.06,27.712 30.19,27.712 h 90.55 c 20.12,0 30.18,-9.237 30.18,-27.712 z" style="fill:#7bf600;fill-rule:nonzero" id="path47" />
<path d="M 1500.75,339.478 V 484.969 H 1368.7 V 0 h 132.05 v 245.948 h 60.37 l 83,-128.17 h 139.59 l -113.18,176.667 113.18,190.524 h -139.59 l -86.78,-145.491 z" style="fill:#7bf600;fill-rule:nonzero" id="path48" />
</g>
</svg>
</a>
</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">{access.frontendToken}</Typography>
</Grid2>
</Grid2>
<Grid2 container>
<Grid2 display="flex" justifyContent="right">
<Chip label="private" size="small" color="warning" />
</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 version={version} 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,37 @@
import {AppBar, Box, Button, Grid2, IconButton, Toolbar, Typography} from "@mui/material";
import MenuIcon from "@mui/icons-material/Menu";
import LanIcon from "@mui/icons-material/Lan";
import ShareIcon from "@mui/icons-material/Share";
interface NavBarProps {
version: string;
shareClick: () => void;
accessClick: () => void;
}
const NavBar = ({ version, shareClick, accessClick }: NavBarProps) => {
return (
<Box ssx={{ flexGrow: 1 }}>
<AppBar position="static">
<Toolbar>
<IconButton size="large" edge="start" color="inherit" aria-label="menu" sx={{ mr: 2 }}>
<MenuIcon />
</IconButton>
<Typography variant="h6" sx={{ flexGrow: 1 }} display={{ xs: "none", sm: "none", md: "block" }}>
zrok Agent { version !== "" ? " | " + version : ""}
</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,64 @@
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">{share.token}</Typography>
</Grid2>
</Grid2>
<Grid2 container>
<Grid2 display="flex" justifyContent="right">
{share.shareMode === "public" && (
<Chip label={share.shareMode} size="small" color="success" />
)}
{share.shareMode === "private" && (
<Chip label={share.shareMode} size="small" color="warning" />
)}
<Chip label={share.backendMode} size="small" color="info" />
</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,15 @@
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,5 @@
/* tslint:disable */
/* eslint-disable */
export * from './runtime';
export * from './apis/index';
export * from './models/index';

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,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: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
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

@ -3,6 +3,7 @@
package proctree package proctree
import ( import (
"github.com/kolesnikovae/go-winjob"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"os/exec" "os/exec"
"sync" "sync"

View File

@ -2,6 +2,7 @@ package proctree
import ( import (
"fmt" "fmt"
_ "github.com/kolesnikovae/go-winjob"
"io" "io"
"os/exec" "os/exec"
"sync" "sync"

View File

@ -1,14 +1,11 @@
package agent package agent
import ( import (
"bytes"
"encoding/json"
"errors" "errors"
"github.com/michaelquigley/pfxlog" "github.com/michaelquigley/pfxlog"
"github.com/openziti/zrok/agent/proctree" "github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/sdk/golang/sdk" "github.com/openziti/zrok/sdk/golang/sdk"
"github.com/sirupsen/logrus"
"strings"
"time" "time"
) )
@ -28,11 +25,8 @@ type share struct {
closed bool closed bool
accessGrants []string accessGrants []string
process *proctree.Child process *proctree.Child
readBuffer bytes.Buffer sub *subordinate.MessageHandler
booted bool
bootComplete chan struct{}
bootErr error
agent *Agent agent *Agent
} }
@ -44,64 +38,46 @@ func (s *share) monitor() {
s.agent.rmShare <- s s.agent.rmShare <- s
} }
func (s *share) tail(data []byte) { func (s *share) bootHandler(msgType string, msg subordinate.Message) error {
defer func() { switch msgType {
if r := recover(); r != nil { case subordinate.BootMessage:
logrus.Errorf("recovering: %v", r) if v, found := msg["token"]; found {
} if str, ok := v.(string); ok {
}() s.token = str
s.readBuffer.Write(data)
if line, err := s.readBuffer.ReadString('\n'); err == nil {
line = strings.Trim(line, "\n")
if !s.booted {
in := make(map[string]interface{})
if err := json.Unmarshal([]byte(line), &in); err == nil {
if v, found := in["token"]; found {
if str, ok := v.(string); ok {
s.token = str
}
}
if v, found := in["backend_mode"]; found {
if str, ok := v.(string); ok {
s.backendMode = sdk.BackendMode(str)
}
}
if v, found := in["share_mode"]; found {
if str, ok := v.(string); ok {
s.shareMode = sdk.ShareMode(str)
}
}
if v, found := in["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 := in["target"]; found {
if str, ok := v.(string); ok {
s.target = str
}
}
s.booted = true
} else {
s.bootErr = errors.New(line)
} }
close(s.bootComplete) }
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
}
}
} else { case subordinate.ErrorMessage:
if strings.HasPrefix(line, "{") { if v, found := msg[subordinate.ErrorMessage]; found {
in := make(map[string]interface{}) if str, ok := v.(string); ok {
if err := json.Unmarshal([]byte(line), &in); err == nil { return errors.New(str)
pfxlog.ChannelLogger(s.token).Info(in)
}
} else {
pfxlog.ChannelLogger(s.token).Info(strings.Trim(line, "\n"))
} }
} }
} else {
s.readBuffer.WriteString(line)
} }
return nil
} }

View File

@ -3,8 +3,10 @@ package agent
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/proctree" "github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/environment" "github.com/openziti/zrok/environment"
"github.com/openziti/zrok/sdk/golang/sdk" "github.com/openziti/zrok/sdk/golang/sdk"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -23,10 +25,20 @@ func (i *agentGrpcImpl) SharePrivate(_ context.Context, req *agentGrpc.SharePriv
shrCmd := []string{os.Args[0], "share", "private", "--subordinate", "-b", req.BackendMode} shrCmd := []string{os.Args[0], "share", "private", "--subordinate", "-b", req.BackendMode}
shr := &share{ shr := &share{
shareMode: sdk.PrivateShareMode, shareMode: sdk.PrivateShareMode,
backendMode: sdk.BackendMode(req.BackendMode), backendMode: sdk.BackendMode(req.BackendMode),
bootComplete: make(chan struct{}), sub: subordinate.NewMessageHandler(),
agent: i.agent, 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 { if req.Insecure {
@ -49,18 +61,22 @@ func (i *agentGrpcImpl) SharePrivate(_ context.Context, req *agentGrpc.SharePriv
logrus.Infof("executing '%v'", shrCmd) logrus.Infof("executing '%v'", shrCmd)
shr.process, err = proctree.StartChild(shr.tail, shrCmd...) shr.process, err = proctree.StartChild(shr.sub.Tail, shrCmd...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
go shr.monitor() <-shr.sub.BootComplete
<-shr.bootComplete
if shr.bootErr == nil { if bootErr == nil {
go shr.monitor()
i.agent.addShare <- shr i.agent.addShare <- shr
return &agentGrpc.SharePrivateResponse{Token: shr.token}, nil 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)
} }
return nil, shr.bootErr
} }

View File

@ -3,8 +3,10 @@ package agent
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/proctree" "github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/environment" "github.com/openziti/zrok/environment"
"github.com/openziti/zrok/sdk/golang/sdk" "github.com/openziti/zrok/sdk/golang/sdk"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -23,10 +25,20 @@ func (i *agentGrpcImpl) SharePublic(_ context.Context, req *agentGrpc.SharePubli
shrCmd := []string{os.Args[0], "share", "public", "--subordinate", "-b", req.BackendMode} shrCmd := []string{os.Args[0], "share", "public", "--subordinate", "-b", req.BackendMode}
shr := &share{ shr := &share{
shareMode: sdk.PublicShareMode, shareMode: sdk.PublicShareMode,
backendMode: sdk.BackendMode(req.BackendMode), backendMode: sdk.BackendMode(req.BackendMode),
bootComplete: make(chan struct{}), sub: subordinate.NewMessageHandler(),
agent: i.agent, 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 { for _, basicAuth := range req.BasicAuth {
@ -73,21 +85,25 @@ func (i *agentGrpcImpl) SharePublic(_ context.Context, req *agentGrpc.SharePubli
logrus.Infof("executing '%v'", shrCmd) logrus.Infof("executing '%v'", shrCmd)
shr.process, err = proctree.StartChild(shr.tail, shrCmd...) shr.process, err = proctree.StartChild(shr.sub.Tail, shrCmd...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
go shr.monitor() <-shr.sub.BootComplete
<-shr.bootComplete
if shr.bootErr == nil { if bootErr == nil {
go shr.monitor()
i.agent.addShare <- shr i.agent.addShare <- shr
return &agentGrpc.SharePublicResponse{ return &agentGrpc.SharePublicResponse{
Token: shr.token, Token: shr.token,
FrontendEndpoints: shr.frontendEndpoints, FrontendEndpoints: shr.frontendEndpoints,
}, nil }, nil
}
return nil, shr.bootErr } 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)
}
} }

View File

@ -3,9 +3,12 @@ package agent
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/agent/proctree" "github.com/openziti/zrok/agent/proctree"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/environment" "github.com/openziti/zrok/environment"
"github.com/sirupsen/logrus"
"os" "os"
) )
@ -21,9 +24,19 @@ func (i *agentGrpcImpl) ShareReserved(_ context.Context, req *agentGrpc.ShareRes
shrCmd := []string{os.Args[0], "share", "reserved", "--subordinate"} shrCmd := []string{os.Args[0], "share", "reserved", "--subordinate"}
shr := &share{ shr := &share{
reserved: true, reserved: true,
bootComplete: make(chan struct{}), sub: subordinate.NewMessageHandler(),
agent: i.agent, 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 != "" { if req.OverrideEndpoint != "" {
@ -38,15 +51,15 @@ func (i *agentGrpcImpl) ShareReserved(_ context.Context, req *agentGrpc.ShareRes
shrCmd = append(shrCmd, req.Token) shrCmd = append(shrCmd, req.Token)
shr.token = req.Token shr.token = req.Token
shr.process, err = proctree.StartChild(shr.tail, shrCmd...) shr.process, err = proctree.StartChild(shr.sub.Tail, shrCmd...)
if err != nil { if err != nil {
return nil, err return nil, err
} }
go shr.monitor() <-shr.sub.BootComplete
<-shr.bootComplete
if shr.bootErr == nil { if bootErr == nil {
go shr.monitor()
i.agent.addShare <- shr i.agent.addShare <- shr
return &agentGrpc.ShareReservedResponse{ return &agentGrpc.ShareReservedResponse{
Token: shr.token, Token: shr.token,
@ -55,7 +68,11 @@ func (i *agentGrpcImpl) ShareReserved(_ context.Context, req *agentGrpc.ShareRes
FrontendEndpoints: shr.frontendEndpoints, FrontendEndpoints: shr.frontendEndpoints,
Target: shr.target, Target: shr.target,
}, nil }, nil
}
return nil, shr.bootErr } 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)
}
} }

View File

@ -3,6 +3,7 @@ package agent
import ( import (
"context" "context"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"sort"
) )
func (i *agentGrpcImpl) Status(_ context.Context, _ *agentGrpc.StatusRequest) (*agentGrpc.StatusResponse, error) { func (i *agentGrpcImpl) Status(_ context.Context, _ *agentGrpc.StatusRequest) (*agentGrpc.StatusResponse, error) {
@ -15,6 +16,9 @@ func (i *agentGrpcImpl) Status(_ context.Context, _ *agentGrpc.StatusRequest) (*
ResponseHeaders: acc.responseHeaders, ResponseHeaders: acc.responseHeaders,
}) })
} }
sort.Slice(accesses, func(i, j int) bool {
return accesses[i].FrontendToken < accesses[j].FrontendToken
})
var shares []*agentGrpc.ShareDetail var shares []*agentGrpc.ShareDetail
for token, shr := range i.agent.shares { for token, shr := range i.agent.shares {
@ -23,11 +27,14 @@ func (i *agentGrpcImpl) Status(_ context.Context, _ *agentGrpc.StatusRequest) (*
ShareMode: string(shr.shareMode), ShareMode: string(shr.shareMode),
BackendMode: string(shr.backendMode), BackendMode: string(shr.backendMode),
Reserved: shr.reserved, Reserved: shr.reserved,
FrontendEndpoint: shr.frontendSelection, FrontendEndpoint: shr.frontendEndpoints,
BackendEndpoint: shr.target, BackendEndpoint: shr.target,
Closed: shr.closed, 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 return &agentGrpc.StatusResponse{Accesses: accesses, Shares: shares}, nil
} }

View File

@ -10,5 +10,8 @@ import (
func (i *agentGrpcImpl) Version(_ context.Context, _ *agentGrpc.VersionRequest) (*agentGrpc.VersionResponse, error) { func (i *agentGrpcImpl) Version(_ context.Context, _ *agentGrpc.VersionRequest) (*agentGrpc.VersionResponse, error) {
v := build.String() v := build.String()
logrus.Debugf("responding to version inquiry with '%v'", v) logrus.Debugf("responding to version inquiry with '%v'", v)
return &agentGrpc.VersionResponse{V: v}, nil return &agentGrpc.VersionResponse{
V: v,
ConsoleEndpoint: i.agent.httpEndpoint,
}, nil
} }

View File

@ -1,7 +1,14 @@
#!/bin/sh #!/bin/sh
protoc --go_out=. \ go install \
--go_opt=paths=source_relative \ github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway \
--go-grpc_out=. \ github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2 \
--go-grpc_opt=paths=source_relative \ 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 agent/agentGrpc/agent.proto

View File

@ -42,13 +42,16 @@ swagger generate server -P rest_model_zrok.Principal -f "$zrokSpec" -s rest_serv
echo "...generating zrok client" echo "...generating zrok client"
swagger generate client -P rest_model_zrok.Principal -f "$zrokSpec" -c rest_client_zrok -t "$zrokDir" -m "rest_model_zrok" swagger generate client -P rest_model_zrok.Principal -f "$zrokSpec" -c rest_client_zrok -t "$zrokDir" -m "rest_model_zrok"
echo "...generating js client" echo "...generating web console js client"
openapi -s specs/zrok.yml -o ui/src/api -l js openapi -s specs/zrok.yml -o ui/src/api -l js
echo "...generating agent console js client"
openapi-generator-cli generate -i agent/agentGrpc/agent.swagger.json -o agent/agentUi/src/api -g typescript-fetch
echo "...generating ts client" echo "...generating ts client"
openapi-generator-cli generate -i specs/zrok.yml -o sdk/nodejs/sdk/src/zrok/api -g typescript-node 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 client"
swagger-codegen generate -i specs/zrok.yml -o sdk/python/sdk/zrok -c $pythonConfig -l python 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

@ -3,12 +3,14 @@ package main
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/go-openapi/runtime" "github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client" httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/agent/agentClient" "github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/endpoints" "github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/proxy" "github.com/openziti/zrok/endpoints/proxy"
"github.com/openziti/zrok/endpoints/tcpTunnel" "github.com/openziti/zrok/endpoints/tcpTunnel"
@ -20,6 +22,7 @@ import (
"github.com/openziti/zrok/rest_client_zrok/share" "github.com/openziti/zrok/rest_client_zrok/share"
"github.com/openziti/zrok/rest_model_zrok" "github.com/openziti/zrok/rest_model_zrok"
"github.com/openziti/zrok/tui" "github.com/openziti/zrok/tui"
"github.com/openziti/zrok/util"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"net/url" "net/url"
@ -35,6 +38,10 @@ func init() {
type accessPrivateCommand struct { type accessPrivateCommand struct {
bindAddress string bindAddress string
autoMode bool
autoAddress string
autoStartPort uint16
autoEndPort uint16
headless bool headless bool
subordinate bool subordinate bool
forceLocal bool forceLocal bool
@ -60,19 +67,24 @@ func newAccessPrivateCommand() *accessPrivateCommand {
cmd.Flags().BoolVar(&command.forceLocal, "force-local", false, "Skip agent detection and force local mode") 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.Flags().BoolVar(&command.forceAgent, "force-agent", false, "Skip agent detection and force agent mode")
cmd.MarkFlagsMutuallyExclusive("force-local", "force-agent") 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") 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.Flags().StringArrayVar(&command.responseHeaders, "response-header", []string{}, "Add a response header ('key:value')")
cmd.Run = command.run cmd.Run = command.run
return command return command
} }
func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) { func (cmd *accessPrivateCommand) run(_ *cobra.Command, args []string) {
if cmd.subordinate {
logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: time.RFC3339Nano})
}
root, err := environment.LoadRoot() root, err := environment.LoadRoot()
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("error loading environment", err)
}
panic(err)
} }
if !root.IsEnabled() { if !root.IsEnabled() {
@ -102,10 +114,7 @@ func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root)
zrok, err := root.Client() zrok, err := root.Client()
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("unable to create zrok client", err)
}
panic(err)
} }
auth := httptransport.APIKeyAuth("X-TOKEN", "header", root.Environment().Token) auth := httptransport.APIKeyAuth("X-TOKEN", "header", root.Environment().Token)
@ -116,23 +125,19 @@ func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root)
} }
accessResp, err := zrok.Share.Access(req, auth) accessResp, err := zrok.Share.Access(req, auth)
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("unable to access", err)
}
panic(err)
} }
if cmd.subordinate { bindAddress := cmd.bindAddress
data := make(map[string]interface{}) if cmd.autoMode {
data["frontend_token"] = accessResp.Payload.FrontendToken if accessResp.Payload.BackendMode == "udpTunnel" {
data["bind_address"] = cmd.bindAddress cmd.error(errors.New("auto-addressing is not compatible with the 'udpTunnel' backend mode"))
jsonData, err := json.Marshal(data)
if err != nil {
panic(err)
} }
fmt.Println(string(jsonData)) autoAddress, err := util.AutoListenerAddress("tcp", cmd.autoAddress, cmd.autoStartPort, cmd.autoEndPort)
} else { if err != nil {
logrus.Infof("allocated frontend '%v'", accessResp.Payload.FrontendToken) cmd.error(err)
}
bindAddress = autoAddress
} }
protocol := "http://" protocol := "http://"
@ -143,35 +148,26 @@ func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root)
protocol = "udp://" protocol = "udp://"
} }
endpointUrl, err := url.Parse(protocol + cmd.bindAddress) endpointUrl, err := url.Parse(protocol + bindAddress)
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("invalid endpoint address", err)
}
panic(err)
} }
requests := make(chan *endpoints.Request, 1024) requests := make(chan *endpoints.Request, 1024)
switch accessResp.Payload.BackendMode { switch accessResp.Payload.BackendMode {
case "tcpTunnel": case "tcpTunnel":
fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{ fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{
BindAddress: cmd.bindAddress, BindAddress: bindAddress,
IdentityName: root.EnvironmentIdentityName(), IdentityName: root.EnvironmentIdentityName(),
ShrToken: args[0], ShrToken: args[0],
RequestsChan: requests, RequestsChan: requests,
}) })
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("unable to create private access", err)
}
panic(err)
} }
go func() { go func() {
if err := fe.Run(); err != nil { if err := fe.Run(); err != nil {
if !panicInstead { cmd.error(err)
tui.Error("error starting access", err)
}
panic(err)
} }
}() }()
@ -184,39 +180,27 @@ func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root)
IdleTime: time.Minute, IdleTime: time.Minute,
}) })
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("unable to create private frontend", err)
}
panic(err)
} }
go func() { go func() {
if err := fe.Run(); err != nil { if err := fe.Run(); err != nil {
if !panicInstead { cmd.error(err)
tui.Error("error starting frontend", err)
}
panic(err)
} }
}() }()
case "socks": case "socks":
fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{ fe, err := tcpTunnel.NewFrontend(&tcpTunnel.FrontendConfig{
BindAddress: cmd.bindAddress, BindAddress: bindAddress,
IdentityName: root.EnvironmentIdentityName(), IdentityName: root.EnvironmentIdentityName(),
ShrToken: args[0], ShrToken: args[0],
RequestsChan: requests, RequestsChan: requests,
}) })
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("unable to create private access", err)
}
panic(err)
} }
go func() { go func() {
if err := fe.Run(); err != nil { if err := fe.Run(); err != nil {
if !panicInstead { cmd.error(err)
tui.Error("error starting access", err)
}
panic(err)
} }
}() }()
@ -230,38 +214,27 @@ func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root)
RequestsChan: requests, RequestsChan: requests,
}) })
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("unable to create private access", err)
}
panic(err)
} }
go func() { go func() {
if err := fe.Run(); err != nil { if err := fe.Run(); err != nil {
if !panicInstead { cmd.error(err)
tui.Error("error starting access", err)
}
panic(err)
} }
}() }()
default: default:
cfg := proxy.DefaultFrontendConfig(root.EnvironmentIdentityName()) cfg := proxy.DefaultFrontendConfig(root.EnvironmentIdentityName())
cfg.ShrToken = shrToken cfg.ShrToken = shrToken
cfg.Address = cmd.bindAddress cfg.Address = bindAddress
cfg.ResponseHeaders = cmd.responseHeaders cfg.ResponseHeaders = cmd.responseHeaders
cfg.RequestsChan = requests cfg.RequestsChan = requests
fe, err := proxy.NewFrontend(cfg) fe, err := proxy.NewFrontend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error(err)
tui.Error("unable to create private frontend", err)
}
panic(err)
} }
go func() { go func() {
if err := fe.Run(); err != nil { if err := fe.Run(); err != nil {
if !panicInstead { cmd.error(err)
tui.Error("unable to run frontend", err)
}
} }
}() }()
} }
@ -270,10 +243,22 @@ func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root)
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT) signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGHUP, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGQUIT)
go func() { go func() {
<-c <-c
cmd.destroy(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth) cmd.shutdown(accessResp.Payload.FrontendToken, root.Environment().ZitiIdentity, shrToken, zrok, auth)
os.Exit(0) 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 { if cmd.headless {
logrus.Infof("access the zrok share at the following endpoint: %v", endpointUrl.String()) logrus.Infof("access the zrok share at the following endpoint: %v", endpointUrl.String())
for { for {
@ -282,12 +267,12 @@ func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root)
logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path) logrus.Infof("%v -> %v %v", req.RemoteAddr, req.Method, req.Path)
} }
} }
} else if cmd.subordinate { } else if cmd.subordinate {
for { for {
select { select {
case req := <-requests: case req := <-requests:
data := make(map[string]interface{}) data := make(map[string]interface{})
data[subordinate.MessageKey] = "access"
data["remote-address"] = req.RemoteAddr data["remote-address"] = req.RemoteAddr
data["method"] = req.Method data["method"] = req.Method
data["path"] = req.Path data["path"] = req.Path
@ -320,11 +305,21 @@ func (cmd *accessPrivateCommand) accessLocal(args []string, root env_core.Root)
} }
close(requests) close(requests)
cmd.destroy(accessResp.Payload.FrontendToken, root.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) { 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(frontendName, envZId, shrToken string, zrok *rest_client_zrok.Zrok, auth runtime.ClientAuthInfoWriter) {
logrus.Infof("shutting down '%v'", shrToken) logrus.Infof("shutting down '%v'", shrToken)
req := share.NewUnaccessParams() req := share.NewUnaccessParams()
req.Body = &rest_model_zrok.UnaccessRequest{ req.Body = &rest_model_zrok.UnaccessRequest{
@ -346,11 +341,19 @@ func (cmd *accessPrivateCommand) accessAgent(args []string, root env_core.Root)
} }
defer func() { _ = conn.Close() }() defer func() { _ = conn.Close() }()
acc, err := client.AccessPrivate(context.Background(), &agentGrpc.AccessPrivateRequest{ req := &agentGrpc.AccessPrivateRequest{
Token: args[0], Token: args[0],
BindAddress: cmd.bindAddress, BindAddress: cmd.bindAddress,
ResponseHeaders: cmd.responseHeaders, 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 { if err != nil {
tui.Error("error creating access", err) tui.Error("error creating access", err)
} }

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

@ -15,7 +15,10 @@ func init() {
} }
type agentStartCommand struct { type agentStartCommand struct {
cmd *cobra.Command cmd *cobra.Command
consoleAddress string
consoleStartPort uint16
consoleEndPort uint16
} }
func newAgentStartCommand() *agentStartCommand { func newAgentStartCommand() *agentStartCommand {
@ -26,6 +29,9 @@ func newAgentStartCommand() *agentStartCommand {
} }
command := &agentStartCommand{cmd: cmd} command := &agentStartCommand{cmd: cmd}
cmd.Run = command.run 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 return command
} }
@ -39,7 +45,11 @@ func (cmd *agentStartCommand) run(_ *cobra.Command, _ []string) {
tui.Error("unable to load environment; did you 'zrok enable'?", nil) tui.Error("unable to load environment; did you 'zrok enable'?", nil)
} }
a, err := agent.NewAgent(root) cfg := agent.DefaultConfig()
cfg.ConsoleAddress = cmd.consoleAddress
cfg.ConsoleStartPort = cmd.consoleStartPort
cfg.ConsoleEndPort = cmd.consoleEndPort
a, err := agent.NewAgent(cfg, root)
if err != nil { if err != nil {
tui.Error("error creating agent", err) tui.Error("error creating agent", err)
} }

View File

@ -2,6 +2,7 @@ package main
import ( import (
"context" "context"
"fmt"
"github.com/openziti/zrok/agent/agentClient" "github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/environment" "github.com/openziti/zrok/environment"
@ -38,12 +39,12 @@ func (cmd *agentVersionCommand) run(_ *cobra.Command, _ []string) {
if err != nil { if err != nil {
tui.Error("error connecting to agent", err) tui.Error("error connecting to agent", err)
} }
defer conn.Close() defer func() { _ = conn.Close() }()
v, err := client.Version(context.Background(), &agentGrpc.VersionRequest{}) v, err := client.Version(context.Background(), &agentGrpc.VersionRequest{})
if err != nil { if err != nil {
tui.Error("error getting agent version", err) tui.Error("error getting agent version", err)
} }
println(v.GetV()) fmt.Printf("%v\n%v\n", v.GetV(), v.GetConsoleEndpoint())
} }

View File

@ -19,7 +19,7 @@ func newConsoleCommand() *consoleCommand {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "console", Use: "console",
Short: "Open the web console", Short: "Open the web console",
Args: cobra.ExactArgs(0), Args: cobra.NoArgs,
} }
command := &consoleCommand{cmd} command := &consoleCommand{cmd}
cmd.Run = command.run cmd.Run = command.run

View File

@ -7,6 +7,7 @@ import (
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/openziti/zrok/agent/agentClient" "github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/endpoints" "github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/drive" "github.com/openziti/zrok/endpoints/drive"
"github.com/openziti/zrok/endpoints/proxy" "github.com/openziti/zrok/endpoints/proxy"
@ -18,6 +19,7 @@ import (
"github.com/openziti/zrok/environment/env_core" "github.com/openziti/zrok/environment/env_core"
"github.com/openziti/zrok/sdk/golang/sdk" "github.com/openziti/zrok/sdk/golang/sdk"
"github.com/openziti/zrok/tui" "github.com/openziti/zrok/tui"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"net" "net"
@ -25,6 +27,7 @@ import (
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"syscall" "syscall"
"time"
) )
func init() { func init() {
@ -69,12 +72,13 @@ func newSharePrivateCommand() *sharePrivateCommand {
} }
func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) { func (cmd *sharePrivateCommand) run(_ *cobra.Command, args []string) {
if cmd.subordinate {
logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: time.RFC3339Nano})
}
root, err := environment.LoadRoot() root, err := environment.LoadRoot()
if err != nil { if err != nil {
if !panicInstead { cmd.error("error loading environment", err)
tui.Error("error loading environment", err)
}
panic(err)
} }
if !root.IsEnabled() { if !root.IsEnabled() {
@ -105,51 +109,48 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
switch cmd.backendMode { switch cmd.backendMode {
case "proxy": case "proxy":
if len(args) != 1 { if len(args) != 1 {
tui.Error("the 'proxy' backend mode expects a <target>", nil) cmd.error("unable to create share", errors.New("the 'proxy' backend mode expects a <target>"))
} }
v, err := parseUrl(args[0]) v, err := parseUrl(args[0])
if err != nil { if err != nil {
if !panicInstead { cmd.error("invalid target endpoint URL", err)
tui.Error("invalid target endpoint URL", err)
}
panic(err)
} }
target = v target = v
case "web": case "web":
if len(args) != 1 { if len(args) != 1 {
tui.Error("the 'web' backend mode expects a <target>", nil) cmd.error("unable to create share", errors.New("the 'web' backend mode expects a <target>"))
} }
target = args[0] target = args[0]
case "tcpTunnel": case "tcpTunnel":
if len(args) != 1 { if len(args) != 1 {
tui.Error("the 'tcpTunnel' backend mode expects a <target>", nil) cmd.error("unable to create share", errors.New("the 'tcpTunnel' backend mode expects a <target>"))
} }
target = args[0] target = args[0]
case "udpTunnel": case "udpTunnel":
if len(args) != 1 { if len(args) != 1 {
tui.Error("the 'udpTunnel' backend mode expects a <target>", nil) cmd.error("unable to create share", errors.New("the 'udpTunnel' backend mode expects a <target>"))
} }
target = args[0] target = args[0]
case "caddy": case "caddy":
if len(args) != 1 { if len(args) != 1 {
tui.Error("the 'caddy' backend mode expects a <target>", nil) cmd.error("unable to create share", errors.New("the 'caddy' backend mode expects a <target>"))
} }
target = args[0] target = args[0]
cmd.headless = true cmd.headless = true
case "drive": case "drive":
if len(args) != 1 { if len(args) != 1 {
tui.Error("the 'drive' backend mode expects a <target>", nil) cmd.error("unable to create share", errors.New("the 'drive' backend mode expects a <target>"))
} }
target = args[0] target = args[0]
case "socks": case "socks":
if len(args) != 0 { if len(args) != 0 {
tui.Error("the 'socks' backend mode does not expect <target>", nil) cmd.error("unable to create share", errors.New("the 'socks' backend mode expects a <target>"))
} }
target = "socks" target = "socks"
@ -157,7 +158,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
if len(args) == 1 { if len(args) == 1 {
_, _, err := net.ParseCIDR(args[0]) _, _, err := net.ParseCIDR(args[0])
if err != nil { if err != nil {
tui.Error("the 'vpn' backend expect valid CIDR <target>", err) cmd.error("unable to create share", errors.New("the 'vpn' backend mode expects a valid CIDR <target>"))
} }
target = args[0] target = args[0]
} else { } else {
@ -165,27 +166,21 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
} }
default: default:
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode), nil) cmd.error("unable to create share", fmt.Errorf("invalid backend mode '%v'; expected {proxy, web, tcpTunnel, udpTunnel, caddy, drive}", cmd.backendMode))
} }
root, err := environment.LoadRoot() root, err := environment.LoadRoot()
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to load environment", err)
tui.Error("unable to load environment", err)
}
panic(err)
} }
if !root.IsEnabled() { if !root.IsEnabled() {
tui.Error("unable to load environment; did you 'zrok enable'?", nil) cmd.error("unable to create share", errors.New("unable to load environment; did you 'zrok enable'?"))
} }
zif, err := root.ZitiIdentityNamed(root.EnvironmentIdentityName()) zif, err := root.ZitiIdentityNamed(root.EnvironmentIdentityName())
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to load ziti identity configuration", err)
tui.Error("unable to load ziti identity configuration", err)
}
panic(err)
} }
req := &sdk.ShareRequest{ req := &sdk.ShareRequest{
@ -199,21 +194,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
} }
shr, err := sdk.CreateShare(root, req) shr, err := sdk.CreateShare(root, req)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create share", err)
tui.Error("unable to create share", err)
}
panic(err)
}
if cmd.subordinate {
data := make(map[string]interface{})
data["token"] = shr.Token
data["frontend_endpoints"] = shr.FrontendEndpoints
jsonData, err := json.Marshal(data)
if err != nil {
panic(err)
}
fmt.Println(string(jsonData))
} }
shareDescription := fmt.Sprintf("access your share with: %v", tui.Code.Render(fmt.Sprintf("zrok access private %v", shr.Token))) shareDescription := fmt.Sprintf("access your share with: %v", tui.Code.Render(fmt.Sprintf("zrok access private %v", shr.Token)))
@ -244,10 +225,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewBackend(cfg) be, err := proxy.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'proxy' backend", err)
tui.Error("error creating proxy backend", err)
}
panic(err)
} }
go func() { go func() {
@ -266,10 +244,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewCaddyWebBackend(cfg) be, err := proxy.NewCaddyWebBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'web' backend", err)
tui.Error("error creating web backend", err)
}
panic(err)
} }
go func() { go func() {
@ -288,10 +263,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
be, err := tcpTunnel.NewBackend(cfg) be, err := tcpTunnel.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'tcpTunnel' backend", err)
tui.Error("error creating tcpTunnel backend", err)
}
panic(err)
} }
go func() { go func() {
@ -310,10 +282,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
be, err := udpTunnel.NewBackend(cfg) be, err := udpTunnel.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'udpTunnel' backend", err)
tui.Error("error creating udpTunnel backend", err)
}
panic(err)
} }
go func() { go func() {
@ -332,10 +301,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewCaddyfileBackend(cfg) be, err := proxy.NewCaddyfileBackend(cfg)
if err != nil { if err != nil {
cmd.shutdown(root, shr) cmd.shutdown(root, shr)
if !panicInstead { cmd.error("unable to create 'caddy' backend", err)
tui.Error("error creating caddy backend", err)
}
panic(err)
} }
go func() { go func() {
@ -354,10 +320,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
be, err := drive.NewBackend(cfg) be, err := drive.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'drive' backend", err)
tui.Error("error creating drive backend", err)
}
panic(err)
} }
go func() { go func() {
@ -375,10 +338,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
be, err := socks.NewBackend(cfg) be, err := socks.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'socks' backend", err)
tui.Error("error creating socks backend", err)
}
panic(err)
} }
go func() { go func() {
@ -397,10 +357,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
be, err := vpn.NewBackend(cfg) be, err := vpn.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'vpn' backend", err)
tui.Error("error creating VPN backend", err)
}
panic(err)
} }
go func() { go func() {
@ -410,10 +367,22 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
}() }()
default: default:
tui.Error("invalid backend mode", nil) cmd.error("unable to create share", errors.New("invalid backend mode"))
} }
if cmd.headless { if cmd.subordinate {
data := make(map[string]interface{})
data[subordinate.MessageKey] = subordinate.BootMessage
data["token"] = shr.Token
data["frontend_endpoints"] = shr.FrontendEndpoints
jsonData, err := json.Marshal(data)
if err != nil {
cmd.error("unable to create share", err)
}
fmt.Println(string(jsonData))
}
if cmd.headless && !cmd.subordinate {
logrus.Infof("allow other to access your share with the following command:\nzrok access private %v", shr.Token) logrus.Infof("allow other to access your share with the following command:\nzrok access private %v", shr.Token)
for { for {
select { select {
@ -427,6 +396,7 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
select { select {
case req := <-requests: case req := <-requests:
data := make(map[string]interface{}) data := make(map[string]interface{})
data[subordinate.MessageKey] = "access"
data["remote_address"] = req.RemoteAddr data["remote_address"] = req.RemoteAddr
data["method"] = req.Method data["method"] = req.Method
data["path"] = req.Path data["path"] = req.Path
@ -461,6 +431,16 @@ func (cmd *sharePrivateCommand) shareLocal(args []string, root env_core.Root) {
} }
} }
func (cmd *sharePrivateCommand) error(msg string, err error) {
if cmd.subordinate {
subordinateError(errors.Wrap(err, msg))
}
if !panicInstead {
tui.Error(msg, err)
}
panic(errors.Wrap(err, msg))
}
func (cmd *sharePrivateCommand) shutdown(root env_core.Root, shr *sdk.Share) { func (cmd *sharePrivateCommand) shutdown(root env_core.Root, shr *sdk.Share) {
logrus.Debugf("shutting down '%v'", shr.Token) logrus.Debugf("shutting down '%v'", shr.Token)
if err := sdk.DeleteShare(root, shr); err != nil { if err := sdk.DeleteShare(root, shr); err != nil {

View File

@ -8,6 +8,7 @@ import (
"github.com/gobwas/glob" "github.com/gobwas/glob"
"github.com/openziti/zrok/agent/agentClient" "github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/endpoints" "github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/drive" "github.com/openziti/zrok/endpoints/drive"
"github.com/openziti/zrok/endpoints/proxy" "github.com/openziti/zrok/endpoints/proxy"
@ -15,6 +16,7 @@ import (
"github.com/openziti/zrok/environment/env_core" "github.com/openziti/zrok/environment/env_core"
"github.com/openziti/zrok/sdk/golang/sdk" "github.com/openziti/zrok/sdk/golang/sdk"
"github.com/openziti/zrok/tui" "github.com/openziti/zrok/tui"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"os" "os"
@ -84,16 +86,17 @@ func newSharePublicCommand() *sharePublicCommand {
} }
func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) { func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
if cmd.subordinate {
logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: time.RFC3339Nano})
}
root, err := environment.LoadRoot() root, err := environment.LoadRoot()
if err != nil { if err != nil {
if !panicInstead { cmd.error("error loading environment", err)
tui.Error("error loading environment", err)
}
panic(err)
} }
if !root.IsEnabled() { if !root.IsEnabled() {
tui.Error("unable to load environment; did you 'zrok enable'?", nil) cmd.error("unable to create share", errors.New("unable to load environment; did you 'zrok enable'?"))
} }
if cmd.subordinate || cmd.forceLocal { if cmd.subordinate || cmd.forceLocal {
@ -121,10 +124,7 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
case "proxy": case "proxy":
v, err := parseUrl(args[0]) v, err := parseUrl(args[0])
if err != nil { if err != nil {
if !panicInstead { cmd.error("invalid target endpoint URL", err)
tui.Error("invalid target endpoint URL", err)
}
panic(err)
} }
target = v target = v
@ -139,15 +139,12 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
target = args[0] target = args[0]
default: default:
tui.Error(fmt.Sprintf("invalid backend mode '%v'; expected {proxy, web, caddy, drive}", cmd.backendMode), nil) cmd.error("unable to create share", fmt.Errorf("invalid backend mode '%v'; expected {proxy, web, caddy, drive}", cmd.backendMode))
} }
zif, err := root.ZitiIdentityNamed(root.EnvironmentIdentityName()) zif, err := root.ZitiIdentityNamed(root.EnvironmentIdentityName())
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to access ziti identity file", err)
tui.Error("unable to access ziti identity file", err)
}
panic(err)
} }
req := &sdk.ShareRequest{ req := &sdk.ShareRequest{
@ -169,30 +166,13 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
for _, g := range cmd.oauthEmailAddressPatterns { for _, g := range cmd.oauthEmailAddressPatterns {
_, err := glob.Compile(g) _, err := glob.Compile(g)
if err != nil { if err != nil {
if !panicInstead { cmd.error(fmt.Sprintf("unable to create share, invalid oauth email glob (%v)", g), err)
tui.Error(fmt.Sprintf("unable to create share, invalid oauth email glob (%v)", g), err)
}
panic(err)
} }
} }
} }
shr, err := sdk.CreateShare(root, req) shr, err := sdk.CreateShare(root, req)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create share", err)
tui.Error("unable to create share", err)
}
panic(err)
}
if cmd.subordinate {
data := make(map[string]interface{})
data["token"] = shr.Token
data["frontend_endpoints"] = shr.FrontendEndpoints
jsonData, err := json.Marshal(data)
if err != nil {
panic(err)
}
fmt.Println(string(jsonData))
} }
mdl := newShareModel(shr.Token, shr.FrontendEndpoints, sdk.PublicShareMode, sdk.BackendMode(cmd.backendMode)) mdl := newShareModel(shr.Token, shr.FrontendEndpoints, sdk.PublicShareMode, sdk.BackendMode(cmd.backendMode))
@ -222,10 +202,7 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewBackend(cfg) be, err := proxy.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create proxy backend", err)
tui.Error("error creating proxy backend", err)
}
panic(err)
} }
go func() { go func() {
@ -244,10 +221,7 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewCaddyWebBackend(cfg) be, err := proxy.NewCaddyWebBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create web backend", err)
tui.Error("unable to create web backend", err)
}
panic(err)
} }
go func() { go func() {
@ -266,10 +240,7 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewCaddyfileBackend(cfg) be, err := proxy.NewCaddyfileBackend(cfg)
if err != nil { if err != nil {
cmd.shutdown(root, shr) cmd.shutdown(root, shr)
if !panicInstead { cmd.error("unable to create caddy backend", err)
tui.Error("unable to create caddy backend", err)
}
panic(err)
} }
go func() { go func() {
@ -288,10 +259,7 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
be, err := drive.NewBackend(cfg) be, err := drive.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create drive backend", err)
tui.Error("error creating drive backend", err)
}
panic(err)
} }
go func() { go func() {
@ -304,7 +272,19 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
tui.Error("invalid backend mode", nil) tui.Error("invalid backend mode", nil)
} }
if cmd.headless { if cmd.subordinate {
data := make(map[string]interface{})
data[subordinate.MessageKey] = subordinate.BootMessage
data["token"] = shr.Token
data["frontend_endpoints"] = shr.FrontendEndpoints
jsonData, err := json.Marshal(data)
if err != nil {
cmd.error("unable to marshal", err)
}
fmt.Println(string(jsonData))
}
if cmd.headless && !cmd.subordinate {
logrus.Infof("access your zrok share at the following endpoints:\n %v", strings.Join(shr.FrontendEndpoints, "\n")) logrus.Infof("access your zrok share at the following endpoints:\n %v", strings.Join(shr.FrontendEndpoints, "\n"))
for { for {
select { select {
@ -318,6 +298,7 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
select { select {
case req := <-requests: case req := <-requests:
data := make(map[string]interface{}) data := make(map[string]interface{})
data[subordinate.MessageKey] = "access"
data["remote_address"] = req.RemoteAddr data["remote_address"] = req.RemoteAddr
data["method"] = req.Method data["method"] = req.Method
data["path"] = req.Path data["path"] = req.Path
@ -352,6 +333,16 @@ func (cmd *sharePublicCommand) shareLocal(args []string, root env_core.Root) {
} }
} }
func (cmd *sharePublicCommand) error(msg string, err error) {
if cmd.subordinate {
subordinateError(errors.Wrap(err, msg))
}
if !panicInstead {
tui.Error(msg, err)
}
panic(errors.Wrap(err, msg))
}
func (cmd *sharePublicCommand) shutdown(root env_core.Root, shr *sdk.Share) { func (cmd *sharePublicCommand) shutdown(root env_core.Root, shr *sdk.Share) {
logrus.Debugf("shutting down '%v'", shr.Token) logrus.Debugf("shutting down '%v'", shr.Token)
if err := sdk.DeleteShare(root, shr); err != nil { if err := sdk.DeleteShare(root, shr); err != nil {

View File

@ -8,6 +8,7 @@ import (
httptransport "github.com/go-openapi/runtime/client" httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/agent/agentClient" "github.com/openziti/zrok/agent/agentClient"
"github.com/openziti/zrok/agent/agentGrpc" "github.com/openziti/zrok/agent/agentGrpc"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/openziti/zrok/endpoints" "github.com/openziti/zrok/endpoints"
"github.com/openziti/zrok/endpoints/drive" "github.com/openziti/zrok/endpoints/drive"
"github.com/openziti/zrok/endpoints/proxy" "github.com/openziti/zrok/endpoints/proxy"
@ -22,8 +23,10 @@ import (
"github.com/openziti/zrok/rest_model_zrok" "github.com/openziti/zrok/rest_model_zrok"
"github.com/openziti/zrok/sdk/golang/sdk" "github.com/openziti/zrok/sdk/golang/sdk"
"github.com/openziti/zrok/tui" "github.com/openziti/zrok/tui"
"github.com/pkg/errors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"time"
) )
func init() { func init() {
@ -64,16 +67,17 @@ func newShareReservedCommand() *shareReservedCommand {
} }
func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) { func (cmd *shareReservedCommand) run(_ *cobra.Command, args []string) {
if cmd.subordinate {
logrus.SetFormatter(&logrus.JSONFormatter{TimestampFormat: time.RFC3339Nano})
}
root, err := environment.LoadRoot() root, err := environment.LoadRoot()
if err != nil { if err != nil {
if !panicInstead { cmd.error("error loading environment", err)
tui.Error("error loading environment", err)
}
panic(err)
} }
if !root.IsEnabled() { if !root.IsEnabled() {
tui.Error("unable to load environment; did you 'zrok enable'?", nil) cmd.error("unable to create share", errors.New("unable to load environment; did you 'zrok enable'?"))
} }
if cmd.subordinate || cmd.forceLocal { if cmd.subordinate || cmd.forceLocal {
@ -100,20 +104,14 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
zrok, err := root.Client() zrok, err := root.Client()
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create zrok client", err)
tui.Error("unable to create zrok client", err)
}
panic(err)
} }
auth := httptransport.APIKeyAuth("X-TOKEN", "header", root.Environment().Token) auth := httptransport.APIKeyAuth("X-TOKEN", "header", root.Environment().Token)
req := metadata.NewGetShareDetailParams() req := metadata.NewGetShareDetailParams()
req.ShrToken = shrToken req.ShrToken = shrToken
resp, err := zrok.Metadata.GetShareDetail(req, auth) resp, err := zrok.Metadata.GetShareDetail(req, auth)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to retrieve reserved share", err)
tui.Error("unable to retrieve reserved share", err)
}
panic(err)
} }
target = cmd.overrideEndpoint target = cmd.overrideEndpoint
if target == "" { if target == "" {
@ -125,10 +123,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
zif, err := root.ZitiIdentityNamed(root.EnvironmentIdentityName()) zif, err := root.ZitiIdentityNamed(root.EnvironmentIdentityName())
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to load ziti identity configuration", err)
tui.Error("unable to load ziti identity configuration", err)
}
panic(err)
} }
if resp.Payload.BackendMode != "socks" { if resp.Payload.BackendMode != "socks" {
@ -143,10 +138,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
BackendProxyEndpoint: target, BackendProxyEndpoint: target,
} }
if _, err := zrok.Share.UpdateShare(upReq, auth); err != nil { if _, err := zrok.Share.UpdateShare(upReq, auth); err != nil {
if !panicInstead { cmd.error("unable to update backend target", err)
tui.Error("unable to update backend target", err)
}
panic(err)
} }
if !cmd.subordinate { if !cmd.subordinate {
logrus.Infof("updated backend target to: %v", target) logrus.Infof("updated backend target to: %v", target)
@ -166,24 +158,6 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
shareDescription = fmt.Sprintf("access your share with: %v", tui.Code.Render(fmt.Sprintf("zrok access private %v", shrToken))) shareDescription = fmt.Sprintf("access your share with: %v", tui.Code.Render(fmt.Sprintf("zrok access private %v", shrToken)))
} }
if cmd.subordinate {
data := make(map[string]interface{})
data["token"] = resp.Payload.Token
data["backend_mode"] = resp.Payload.BackendMode
data["share_mode"] = resp.Payload.ShareMode
if resp.Payload.FrontendEndpoint != "" {
data["frontend_endpoints"] = resp.Payload.FrontendEndpoint
}
if resp.Payload.BackendProxyEndpoint != "" {
data["target"] = resp.Payload.BackendProxyEndpoint
}
jsonData, err := json.Marshal(data)
if err != nil {
panic(err)
}
fmt.Println(string(jsonData))
}
mdl := newShareModel(shrToken, []string{shareDescription}, sdk.ShareMode(resp.Payload.ShareMode), sdk.BackendMode(resp.Payload.BackendMode)) mdl := newShareModel(shrToken, []string{shareDescription}, sdk.ShareMode(resp.Payload.ShareMode), sdk.BackendMode(resp.Payload.BackendMode))
if !cmd.headless && !cmd.subordinate { if !cmd.headless && !cmd.subordinate {
proxy.SetCaddyLoggingWriter(mdl) proxy.SetCaddyLoggingWriter(mdl)
@ -202,10 +176,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewBackend(cfg) be, err := proxy.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'proxy' backend", err)
tui.Error("unable to create proxy backend handler", err)
}
panic(err)
} }
go func() { go func() {
@ -224,10 +195,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewCaddyWebBackend(cfg) be, err := proxy.NewCaddyWebBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'web' backend", err)
tui.Error("error creating web backend", err)
}
panic(err)
} }
go func() { go func() {
@ -246,10 +214,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
be, err := tcpTunnel.NewBackend(cfg) be, err := tcpTunnel.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'tcpTunnel' backend", err)
tui.Error("error creating tcpTunnel backend", err)
}
panic(err)
} }
go func() { go func() {
@ -268,10 +233,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
be, err := udpTunnel.NewBackend(cfg) be, err := udpTunnel.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'udpTunnel' backend", err)
tui.Error("error creating udpTunnel backend", err)
}
panic(err)
} }
go func() { go func() {
@ -289,10 +251,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
be, err := proxy.NewCaddyfileBackend(cfg) be, err := proxy.NewCaddyfileBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'caddy' backend", err)
tui.Error("error creating caddy backend", err)
}
panic(err)
} }
go func() { go func() {
@ -311,10 +270,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
be, err := drive.NewBackend(cfg) be, err := drive.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'drive' backend", err)
tui.Error("error creating drive backend", err)
}
panic(err)
} }
go func() { go func() {
@ -332,10 +288,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
be, err := socks.NewBackend(cfg) be, err := socks.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'socks' backend", err)
tui.Error("error creating socks backend", err)
}
panic(err)
} }
go func() { go func() {
@ -354,10 +307,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
be, err := vpn.NewBackend(cfg) be, err := vpn.NewBackend(cfg)
if err != nil { if err != nil {
if !panicInstead { cmd.error("unable to create 'vpn' backend", err)
tui.Error("error creating VPN backend", err)
}
panic(err)
} }
go func() { go func() {
@ -367,10 +317,29 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
}() }()
default: default:
tui.Error("invalid backend mode", nil) cmd.error("unable to share", errors.New("invalid backend mode"))
} }
if cmd.headless { if cmd.subordinate {
data := make(map[string]interface{})
data[subordinate.MessageKey] = subordinate.BootMessage
data["token"] = resp.Payload.Token
data["backend_mode"] = resp.Payload.BackendMode
data["share_mode"] = resp.Payload.ShareMode
if resp.Payload.FrontendEndpoint != "" {
data["frontend_endpoints"] = resp.Payload.FrontendEndpoint
}
if resp.Payload.BackendProxyEndpoint != "" {
data["target"] = resp.Payload.BackendProxyEndpoint
}
jsonData, err := json.Marshal(data)
if err != nil {
cmd.error("unable to marshal", err)
}
fmt.Println(string(jsonData))
}
if cmd.headless && !cmd.subordinate {
switch resp.Payload.ShareMode { switch resp.Payload.ShareMode {
case string(sdk.PublicShareMode): case string(sdk.PublicShareMode):
logrus.Infof("access your zrok share: %v", resp.Payload.FrontendEndpoint) logrus.Infof("access your zrok share: %v", resp.Payload.FrontendEndpoint)
@ -390,6 +359,7 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
select { select {
case req := <-requests: case req := <-requests:
data := make(map[string]interface{}) data := make(map[string]interface{})
data[subordinate.MessageKey] = "access"
data["remote-address"] = req.RemoteAddr data["remote-address"] = req.RemoteAddr
data["method"] = req.Method data["method"] = req.Method
data["path"] = req.Path data["path"] = req.Path
@ -423,6 +393,16 @@ func (cmd *shareReservedCommand) shareLocal(args []string, root env_core.Root) {
} }
} }
func (cmd *shareReservedCommand) error(msg string, err error) {
if cmd.subordinate {
subordinateError(errors.Wrap(err, msg))
}
if !panicInstead {
tui.Error(msg, err)
}
panic(errors.Wrap(err, msg))
}
func (cmd *shareReservedCommand) shareAgent(args []string, root env_core.Root) { func (cmd *shareReservedCommand) shareAgent(args []string, root env_core.Root) {
logrus.Info("starting") logrus.Info("starting")

View File

@ -0,0 +1,86 @@
package subordinate
import (
"bytes"
"encoding/json"
"github.com/sirupsen/logrus"
"strings"
)
const (
MessageKey = "msg"
RawMessage = "raw"
BootMessage = "boot"
ErrorMessage = "error"
)
type Message map[string]interface{}
type MessageHandler struct {
BootHandler func(string, Message)
MessageHandler func(Message)
MalformedHandler func(Message)
BootComplete chan struct{}
readBuffer bytes.Buffer
booted bool
}
func NewMessageHandler() *MessageHandler {
return &MessageHandler{
BootComplete: make(chan struct{}),
}
}
func (h *MessageHandler) Tail(data []byte) {
defer func() {
if r := recover(); r != nil {
logrus.Errorf("recovered: %v", r)
}
}()
h.readBuffer.Write(data)
if line, err := h.readBuffer.ReadString('\n'); err == nil {
line = strings.Trim(line, "\n \t")
logrus.Debugf("line: '%v'", line)
msg := make(map[string]interface{})
if !h.booted {
if line[0] == '{' {
if err := json.Unmarshal([]byte(line), &msg); err == nil {
if v, found := msg[MessageKey]; found {
if vStr, ok := v.(string); ok {
if vStr == BootMessage || vStr == ErrorMessage {
h.BootHandler(vStr, msg)
h.booted = true
close(h.BootComplete)
} else {
h.MessageHandler(msg)
}
} else {
h.MalformedHandler(msg)
}
} else {
h.MalformedHandler(msg)
}
} else {
msg[MessageKey] = RawMessage
msg[RawMessage] = line
h.MessageHandler(msg)
}
} else {
msg[MessageKey] = RawMessage
msg[RawMessage] = line
h.MessageHandler(msg)
}
} else {
if line[0] == '{' {
if err := json.Unmarshal([]byte(line), &msg); err != nil {
logrus.Error(line)
}
} else {
msg[MessageKey] = RawMessage
msg[RawMessage] = line
}
h.MessageHandler(msg)
}
}
}

View File

@ -1,9 +1,11 @@
package main package main
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/go-openapi/runtime" "github.com/go-openapi/runtime"
httptransport "github.com/go-openapi/runtime/client" httptransport "github.com/go-openapi/runtime/client"
"github.com/openziti/zrok/cmd/zrok/subordinate"
"github.com/pkg/errors" "github.com/pkg/errors"
"math" "math"
"net/url" "net/url"
@ -45,3 +47,15 @@ func parseUrl(in string) (string, error) {
return targetEndpoint.String(), nil return targetEndpoint.String(), nil
} }
func subordinateError(err error) {
msg := make(map[string]interface{})
msg[subordinate.MessageKey] = subordinate.ErrorMessage
msg[subordinate.ErrorMessage] = err.Error()
if data, err := json.Marshal(msg); err == nil {
fmt.Println(string(data))
} else {
fmt.Println("{\"" + subordinate.MessageKey + "\":\"" + subordinate.ErrorMessage + "\",\"" + subordinate.ErrorMessage + "\":\"internal error\"}")
}
os.Exit(1)
}

14
go.mod
View File

@ -23,12 +23,14 @@ require (
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/gorilla/websocket v1.5.3 github.com/gorilla/websocket v1.5.3
github.com/greenpau/caddy-security v1.1.29 github.com/greenpau/caddy-security v1.1.29
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0
github.com/iancoleman/strcase v0.3.0 github.com/iancoleman/strcase v0.3.0
github.com/influxdata/influxdb-client-go/v2 v2.11.0 github.com/influxdata/influxdb-client-go/v2 v2.11.0
github.com/jaevor/go-nanoid v1.3.0 github.com/jaevor/go-nanoid v1.3.0
github.com/jedib0t/go-pretty/v6 v6.5.9 github.com/jedib0t/go-pretty/v6 v6.5.9
github.com/jessevdk/go-flags v1.6.1 github.com/jessevdk/go-flags v1.6.1
github.com/jmoiron/sqlx v1.3.5 github.com/jmoiron/sqlx v1.3.5
github.com/kolesnikovae/go-winjob v1.0.0
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9
github.com/mattn/go-sqlite3 v1.14.18 github.com/mattn/go-sqlite3 v1.14.18
github.com/michaelquigley/cf v0.0.13 github.com/michaelquigley/cf v0.0.13
@ -61,13 +63,15 @@ require (
golang.org/x/oauth2 v0.23.0 golang.org/x/oauth2 v0.23.0
golang.org/x/sys v0.25.0 golang.org/x/sys v0.25.0
golang.org/x/time v0.6.0 golang.org/x/time v0.6.0
google.golang.org/grpc v1.65.0 google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142
google.golang.org/grpc v1.67.1
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1
google.golang.org/protobuf v1.34.2 google.golang.org/protobuf v1.34.2
nhooyr.io/websocket v1.8.17 nhooyr.io/websocket v1.8.17
) )
require ( require (
cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/compute/metadata v0.5.0 // indirect
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
@ -132,7 +136,7 @@ require (
github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.2.1 // indirect github.com/gobwas/ws v1.2.1 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang/glog v1.2.1 // indirect github.com/golang/glog v1.2.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/cel-go v0.20.1 // indirect github.com/google/cel-go v0.20.1 // indirect
@ -145,7 +149,6 @@ require (
github.com/gorilla/securecookie v1.1.2 // indirect github.com/gorilla/securecookie v1.1.2 // indirect
github.com/greenpau/go-authcrunch v1.1.4 // indirect github.com/greenpau/go-authcrunch v1.1.4 // indirect
github.com/greenpau/versioned v1.0.30 // indirect github.com/greenpau/versioned v1.0.30 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
@ -266,8 +269,7 @@ require (
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 // indirect golang.zx2c4.com/wireguard v0.0.0-20220703234212-c31a7b1ab478 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect

25
go.sum
View File

@ -29,8 +29,8 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
@ -334,8 +334,8 @@ github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY=
github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -588,6 +588,8 @@ github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ib
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/kolesnikovae/go-winjob v1.0.0 h1:OKEtCHB3sYNAiqNwGDhf08Y6luM7C8mP+42rp1N6SeE=
github.com/kolesnikovae/go-winjob v1.0.0/go.mod h1:k0joOLP3/NBrRmDQjPV2+oN1TPmEWt6arTNtFjVeQuM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
@ -1223,6 +1225,7 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200826173525-f9321e4c35a6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -1440,10 +1443,10 @@ google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaE
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw= google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda h1:wu/KJm9KJwpfHWhkkZGohVC6KRrc1oJNr4jwtQMOQXw=
google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw= google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda/go.mod h1:g2LLCvCeCSir/JJSWosk19BR4NVxGqHUC6rxIRsd7Aw=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 h1:wKguEg1hsxI2/L3hUYrpo1RVi48K+uTyzKqprwLXsb8=
google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142/go.mod h1:d6be+8HhtEtucleCbxpPW9PA9XwISACu8nvpPqF0BVo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -1464,8 +1467,10 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@ -0,0 +1,31 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
import "google/api/http.proto";
import "google/protobuf/descriptor.proto";
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "AnnotationsProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
extend google.protobuf.MethodOptions {
// See `HttpRule`.
HttpRule http = 72295728;
}

View File

@ -0,0 +1,104 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
import "google/protobuf/descriptor.proto";
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "FieldBehaviorProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
extend google.protobuf.FieldOptions {
// A designation of a specific field behavior (required, output only, etc.)
// in protobuf messages.
//
// Examples:
//
// string name = 1 [(google.api.field_behavior) = REQUIRED];
// State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
// google.protobuf.Duration ttl = 1
// [(google.api.field_behavior) = INPUT_ONLY];
// google.protobuf.Timestamp expire_time = 1
// [(google.api.field_behavior) = OUTPUT_ONLY,
// (google.api.field_behavior) = IMMUTABLE];
repeated google.api.FieldBehavior field_behavior = 1052 [packed = false];
}
// An indicator of the behavior of a given field (for example, that a field
// is required in requests, or given as output but ignored as input).
// This **does not** change the behavior in protocol buffers itself; it only
// denotes the behavior and may affect how API tooling handles the field.
//
// Note: This enum **may** receive new values in the future.
enum FieldBehavior {
// Conventional default for enums. Do not use this.
FIELD_BEHAVIOR_UNSPECIFIED = 0;
// Specifically denotes a field as optional.
// While all fields in protocol buffers are optional, this may be specified
// for emphasis if appropriate.
OPTIONAL = 1;
// Denotes a field as required.
// This indicates that the field **must** be provided as part of the request,
// and failure to do so will cause an error (usually `INVALID_ARGUMENT`).
REQUIRED = 2;
// Denotes a field as output only.
// This indicates that the field is provided in responses, but including the
// field in a request does nothing (the server *must* ignore it and
// *must not* throw an error as a result of the field's presence).
OUTPUT_ONLY = 3;
// Denotes a field as input only.
// This indicates that the field is provided in requests, and the
// corresponding field is not included in output.
INPUT_ONLY = 4;
// Denotes a field as immutable.
// This indicates that the field may be set once in a request to create a
// resource, but may not be changed thereafter.
IMMUTABLE = 5;
// Denotes that a (repeated) field is an unordered list.
// This indicates that the service may provide the elements of the list
// in any arbitrary order, rather than the order the user originally
// provided. Additionally, the list's order may or may not be stable.
UNORDERED_LIST = 6;
// Denotes that this field returns a non-empty default value if not set.
// This indicates that if the user provides the empty value in a request,
// a non-empty value will be returned. The user will not be aware of what
// non-empty value to expect.
NON_EMPTY_DEFAULT = 7;
// Denotes that the field in a resource (a message annotated with
// google.api.resource) is used in the resource name to uniquely identify the
// resource. For AIP-compliant APIs, this should only be applied to the
// `name` field on the resource.
//
// This behavior should not be applied to references to other resources within
// the message.
//
// The identifier field of resources often have different field behavior
// depending on the request it is embedded in (e.g. for Create methods name
// is optional and unused, while for Update methods it is required). Instead
// of method-specific annotations, only `IDENTIFIER` is required.
IDENTIFIER = 8;
}

371
google/api/http.proto Normal file
View File

@ -0,0 +1,371 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
option cc_enable_arenas = true;
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
option java_multiple_files = true;
option java_outer_classname = "HttpProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
// Defines the HTTP configuration for an API service. It contains a list of
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
// to one or more HTTP REST API methods.
message Http {
// A list of HTTP configuration rules that apply to individual API methods.
//
// **NOTE:** All service configuration rules follow "last one wins" order.
repeated HttpRule rules = 1;
// When set to true, URL path parameters will be fully URI-decoded except in
// cases of single segment matches in reserved expansion, where "%2F" will be
// left encoded.
//
// The default behavior is to not decode RFC 6570 reserved characters in multi
// segment matches.
bool fully_decode_reserved_expansion = 2;
}
// gRPC Transcoding
//
// gRPC Transcoding is a feature for mapping between a gRPC method and one or
// more HTTP REST endpoints. It allows developers to build a single API service
// that supports both gRPC APIs and REST APIs. Many systems, including [Google
// APIs](https://github.com/googleapis/googleapis),
// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
// and use it for large scale production services.
//
// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
// how different portions of the gRPC request message are mapped to the URL
// path, URL query parameters, and HTTP request body. It also controls how the
// gRPC response message is mapped to the HTTP response body. `HttpRule` is
// typically specified as an `google.api.http` annotation on the gRPC method.
//
// Each mapping specifies a URL path template and an HTTP method. The path
// template may refer to one or more fields in the gRPC request message, as long
// as each field is a non-repeated field with a primitive (non-message) type.
// The path template controls how fields of the request message are mapped to
// the URL path.
//
// Example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get: "/v1/{name=messages/*}"
// };
// }
// }
// message GetMessageRequest {
// string name = 1; // Mapped to URL path.
// }
// message Message {
// string text = 1; // The resource content.
// }
//
// This enables an HTTP REST to gRPC mapping as below:
//
// - HTTP: `GET /v1/messages/123456`
// - gRPC: `GetMessage(name: "messages/123456")`
//
// Any fields in the request message which are not bound by the path template
// automatically become HTTP query parameters if there is no HTTP request body.
// For example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get:"/v1/messages/{message_id}"
// };
// }
// }
// message GetMessageRequest {
// message SubMessage {
// string subfield = 1;
// }
// string message_id = 1; // Mapped to URL path.
// int64 revision = 2; // Mapped to URL query parameter `revision`.
// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
// }
//
// This enables a HTTP JSON to RPC mapping as below:
//
// - HTTP: `GET /v1/messages/123456?revision=2&sub.subfield=foo`
// - gRPC: `GetMessage(message_id: "123456" revision: 2 sub:
// SubMessage(subfield: "foo"))`
//
// Note that fields which are mapped to URL query parameters must have a
// primitive type or a repeated primitive type or a non-repeated message type.
// In the case of a repeated type, the parameter can be repeated in the URL
// as `...?param=A&param=B`. In the case of a message type, each field of the
// message is mapped to a separate parameter, such as
// `...?foo.a=A&foo.b=B&foo.c=C`.
//
// For HTTP methods that allow a request body, the `body` field
// specifies the mapping. Consider a REST update method on the
// message resource collection:
//
// service Messaging {
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
// option (google.api.http) = {
// patch: "/v1/messages/{message_id}"
// body: "message"
// };
// }
// }
// message UpdateMessageRequest {
// string message_id = 1; // mapped to the URL
// Message message = 2; // mapped to the body
// }
//
// The following HTTP JSON to RPC mapping is enabled, where the
// representation of the JSON in the request body is determined by
// protos JSON encoding:
//
// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }`
// - gRPC: `UpdateMessage(message_id: "123456" message { text: "Hi!" })`
//
// The special name `*` can be used in the body mapping to define that
// every field not bound by the path template should be mapped to the
// request body. This enables the following alternative definition of
// the update method:
//
// service Messaging {
// rpc UpdateMessage(Message) returns (Message) {
// option (google.api.http) = {
// patch: "/v1/messages/{message_id}"
// body: "*"
// };
// }
// }
// message Message {
// string message_id = 1;
// string text = 2;
// }
//
//
// The following HTTP JSON to RPC mapping is enabled:
//
// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }`
// - gRPC: `UpdateMessage(message_id: "123456" text: "Hi!")`
//
// Note that when using `*` in the body mapping, it is not possible to
// have HTTP parameters, as all fields not bound by the path end in
// the body. This makes this option more rarely used in practice when
// defining REST APIs. The common usage of `*` is in custom methods
// which don't use the URL at all for transferring data.
//
// It is possible to define multiple HTTP methods for one RPC by using
// the `additional_bindings` option. Example:
//
// service Messaging {
// rpc GetMessage(GetMessageRequest) returns (Message) {
// option (google.api.http) = {
// get: "/v1/messages/{message_id}"
// additional_bindings {
// get: "/v1/users/{user_id}/messages/{message_id}"
// }
// };
// }
// }
// message GetMessageRequest {
// string message_id = 1;
// string user_id = 2;
// }
//
// This enables the following two alternative HTTP JSON to RPC mappings:
//
// - HTTP: `GET /v1/messages/123456`
// - gRPC: `GetMessage(message_id: "123456")`
//
// - HTTP: `GET /v1/users/me/messages/123456`
// - gRPC: `GetMessage(user_id: "me" message_id: "123456")`
//
// Rules for HTTP mapping
//
// 1. Leaf request fields (recursive expansion nested messages in the request
// message) are classified into three categories:
// - Fields referred by the path template. They are passed via the URL path.
// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They
// are passed via the HTTP
// request body.
// - All other fields are passed via the URL query parameters, and the
// parameter name is the field path in the request message. A repeated
// field can be represented as multiple query parameters under the same
// name.
// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL
// query parameter, all fields
// are passed via URL path and HTTP request body.
// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP
// request body, all
// fields are passed via URL path and URL query parameters.
//
// Path template syntax
//
// Template = "/" Segments [ Verb ] ;
// Segments = Segment { "/" Segment } ;
// Segment = "*" | "**" | LITERAL | Variable ;
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
// FieldPath = IDENT { "." IDENT } ;
// Verb = ":" LITERAL ;
//
// The syntax `*` matches a single URL path segment. The syntax `**` matches
// zero or more URL path segments, which must be the last part of the URL path
// except the `Verb`.
//
// The syntax `Variable` matches part of the URL path as specified by its
// template. A variable template must not contain other variables. If a variable
// matches a single path segment, its template may be omitted, e.g. `{var}`
// is equivalent to `{var=*}`.
//
// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
// contains any reserved character, such characters should be percent-encoded
// before the matching.
//
// If a variable contains exactly one path segment, such as `"{var}"` or
// `"{var=*}"`, when such a variable is expanded into a URL path on the client
// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
// server side does the reverse decoding. Such variables show up in the
// [Discovery
// Document](https://developers.google.com/discovery/v1/reference/apis) as
// `{var}`.
//
// If a variable contains multiple path segments, such as `"{var=foo/*}"`
// or `"{var=**}"`, when such a variable is expanded into a URL path on the
// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
// The server side does the reverse decoding, except "%2F" and "%2f" are left
// unchanged. Such variables show up in the
// [Discovery
// Document](https://developers.google.com/discovery/v1/reference/apis) as
// `{+var}`.
//
// Using gRPC API Service Configuration
//
// gRPC API Service Configuration (service config) is a configuration language
// for configuring a gRPC service to become a user-facing product. The
// service config is simply the YAML representation of the `google.api.Service`
// proto message.
//
// As an alternative to annotating your proto file, you can configure gRPC
// transcoding in your service config YAML files. You do this by specifying a
// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
// effect as the proto annotation. This can be particularly useful if you
// have a proto that is reused in multiple services. Note that any transcoding
// specified in the service config will override any matching transcoding
// configuration in the proto.
//
// The following example selects a gRPC method and applies an `HttpRule` to it:
//
// http:
// rules:
// - selector: example.v1.Messaging.GetMessage
// get: /v1/messages/{message_id}/{sub.subfield}
//
// Special notes
//
// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
// proto to JSON conversion must follow the [proto3
// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
//
// While the single segment variable follows the semantics of
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
// Expansion, the multi segment variable **does not** follow RFC 6570 Section
// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
// does not expand special characters like `?` and `#`, which would lead
// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
// for multi segment variables.
//
// The path variables **must not** refer to any repeated or mapped field,
// because client libraries are not capable of handling such variable expansion.
//
// The path variables **must not** capture the leading "/" character. The reason
// is that the most common use case "{var}" does not capture the leading "/"
// character. For consistency, all path variables must share the same behavior.
//
// Repeated message fields must not be mapped to URL query parameters, because
// no client library can support such complicated mapping.
//
// If an API needs to use a JSON array for request or response body, it can map
// the request or response body to a repeated field. However, some gRPC
// Transcoding implementations may not support this feature.
message HttpRule {
// Selects a method to which this rule applies.
//
// Refer to [selector][google.api.DocumentationRule.selector] for syntax
// details.
string selector = 1;
// Determines the URL pattern is matched by this rules. This pattern can be
// used with any of the {get|put|post|delete|patch} methods. A custom method
// can be defined using the 'custom' field.
oneof pattern {
// Maps to HTTP GET. Used for listing and getting information about
// resources.
string get = 2;
// Maps to HTTP PUT. Used for replacing a resource.
string put = 3;
// Maps to HTTP POST. Used for creating a resource or performing an action.
string post = 4;
// Maps to HTTP DELETE. Used for deleting a resource.
string delete = 5;
// Maps to HTTP PATCH. Used for updating a resource.
string patch = 6;
// The custom pattern is used for specifying an HTTP method that is not
// included in the `pattern` field, such as HEAD, or "*" to leave the
// HTTP method unspecified for this rule. The wild-card rule is useful
// for services that provide content to Web (HTML) clients.
CustomHttpPattern custom = 8;
}
// The name of the request field whose value is mapped to the HTTP request
// body, or `*` for mapping all request fields not captured by the path
// pattern to the HTTP body, or omitted for not having any HTTP request body.
//
// NOTE: the referred field must be present at the top-level of the request
// message type.
string body = 7;
// Optional. The name of the response field whose value is mapped to the HTTP
// response body. When omitted, the entire response message will be used
// as the HTTP response body.
//
// NOTE: The referred field must be present at the top-level of the response
// message type.
string response_body = 12;
// Additional HTTP bindings for the selector. Nested bindings must
// not contain an `additional_bindings` field themselves (that is,
// the nesting may only be one level deep).
repeated HttpRule additional_bindings = 11;
}
// A custom pattern is used for defining custom HTTP verb.
message CustomHttpPattern {
// The name of this custom HTTP verb.
string kind = 1;
// The path matched by this custom verb.
string path = 2;
}

81
google/api/httpbody.proto Normal file
View File

@ -0,0 +1,81 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
package google.api;
import "google/protobuf/any.proto";
option cc_enable_arenas = true;
option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody";
option java_multiple_files = true;
option java_outer_classname = "HttpBodyProto";
option java_package = "com.google.api";
option objc_class_prefix = "GAPI";
// Message that represents an arbitrary HTTP body. It should only be used for
// payload formats that can't be represented as JSON, such as raw binary or
// an HTML page.
//
//
// This message can be used both in streaming and non-streaming API methods in
// the request as well as the response.
//
// It can be used as a top-level request field, which is convenient if one
// wants to extract parameters from either the URL or HTTP template into the
// request fields and also want access to the raw HTTP body.
//
// Example:
//
// message GetResourceRequest {
// // A unique request id.
// string request_id = 1;
//
// // The raw HTTP body is bound to this field.
// google.api.HttpBody http_body = 2;
//
// }
//
// service ResourceService {
// rpc GetResource(GetResourceRequest)
// returns (google.api.HttpBody);
// rpc UpdateResource(google.api.HttpBody)
// returns (google.protobuf.Empty);
//
// }
//
// Example with streaming methods:
//
// service CaldavService {
// rpc GetCalendar(stream google.api.HttpBody)
// returns (stream google.api.HttpBody);
// rpc UpdateCalendar(stream google.api.HttpBody)
// returns (stream google.api.HttpBody);
//
// }
//
// Use of this type only changes how the request and response bodies are
// handled, all other features will continue to work unchanged.
message HttpBody {
// The HTTP Content-Type header value specifying the content type of the body.
string content_type = 1;
// The HTTP request/response body as raw binary.
bytes data = 2;
// Application specific response metadata. Must be set in the first response
// for streaming APIs.
repeated google.protobuf.Any extensions = 3;
}

29
util/autoListener.go Normal file
View File

@ -0,0 +1,29 @@
package util
import (
"fmt"
"net"
)
func AutoListener(protocol, address string, startPort, endPort uint16) (net.Listener, error) {
for i := startPort; i <= endPort; i++ {
l, err := net.Listen(protocol, fmt.Sprintf("%s:%d", address, i))
if err != nil {
continue
}
return l, nil
}
return nil, fmt.Errorf("no listener found in range")
}
func AutoListenerAddress(protocol, address string, startPort, endPort uint16) (string, error) {
listener, err := AutoListener(protocol, address, startPort, endPort)
if err != nil {
return "", err
}
autoAddress := listener.Addr().String()
if err := listener.Close(); err != nil {
return "", err
}
return autoAddress, nil
}

15
util/cors.go Normal file
View File

@ -0,0 +1,15 @@
package util
import "net/http"
func cors(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PATCH, DELETE")
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, Authorization, ResponseType, User-Agent")
if r.Method == "OPTIONS" {
return
}
h.ServeHTTP(w, r)
})
}