зеркало из https://github.com/golang/build.git
internal/gomote, internal/coordinator/remote: add the sign SSH key endpoint implementation
This change adds the implementation for the sign SSH key endpoint. The endpoint accepts a public SSH key and signs it with the gomote server's certificate authority. The certificate added to the public key will be used to validate if the certificate authority was used to sign the certificate. It will also be used to determine if the requestor has rights to initiate and SSH session with the gomote instance being requested. This is part of a shift to OpenSSH certificate authentication in the gomote SSH server. For golang/go#47521 Updates golang/go#48742 Change-Id: I427b34c7f006ae20f5643322dc0754bf7a82e5f1 Reviewed-on: https://go-review.googlesource.com/c/build/+/391516 Trust: Carlos Amedee <carlos@golang.org> Run-TryBot: Carlos Amedee <carlos@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
Родитель
289767d327
Коммит
862e04a161
|
@ -341,6 +341,7 @@ func main() {
|
|||
if err := loadStatic(); err != nil {
|
||||
log.Printf("Failed to load static resources: %v", err)
|
||||
}
|
||||
sshCA := mustRetrieveSSHCertificateAuthority()
|
||||
|
||||
var opts []grpc.ServerOption
|
||||
if *buildEnvName == "" && *mode != "dev" && metadata.OnGCE() {
|
||||
|
@ -362,7 +363,7 @@ func main() {
|
|||
dashV1 := legacydash.Handler(gce.GoDSClient(), maintnerClient, string(masterKey()), grpcServer)
|
||||
dashV2 := &builddash.Handler{Datastore: gce.GoDSClient(), Maintner: maintnerClient}
|
||||
gs := &gRPCServer{dashboardURL: "https://build.golang.org"}
|
||||
gomoteServer := gomote.New(remote.NewSessionPool(context.Background()), sched)
|
||||
gomoteServer := gomote.New(remote.NewSessionPool(context.Background()), sched, sshCA)
|
||||
protos.RegisterCoordinatorServer(grpcServer, gs)
|
||||
gomoteprotos.RegisterGomoteServiceServer(grpcServer, gomoteServer)
|
||||
mux.HandleFunc("/", grpcHandlerFunc(grpcServer, handleStatus)) // Serve a status page at farmer.golang.org.
|
||||
|
@ -2214,3 +2215,11 @@ func mustCreateEC2BuildletPool(sc *secret.Client) *pool.EC2Buildlet {
|
|||
}
|
||||
return ec2Pool
|
||||
}
|
||||
|
||||
func mustRetrieveSSHCertificateAuthority() (privateKey []byte) {
|
||||
privateKey, _, err := remote.SSHKeyPair()
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create SSH CA cert: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package remote
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// SignPublicSSHKey signs a public SSH key using the certificate authority. These keys are intended for use with the specified gomote and owner.
|
||||
// The public SSH are intended to be used in OpenSSH certificate authentication with the gomote SSH server.
|
||||
func SignPublicSSHKey(ctx context.Context, caPriKey ssh.Signer, rawPubKey []byte, sessionID, ownerID string, d time.Duration) ([]byte, error) {
|
||||
pubKey, _, _, _, err := ssh.ParseAuthorizedKey(rawPubKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse public key=%w", err)
|
||||
}
|
||||
cert := &ssh.Certificate{
|
||||
Key: pubKey,
|
||||
Serial: 1,
|
||||
CertType: ssh.UserCert,
|
||||
KeyId: "go_build",
|
||||
ValidPrincipals: []string{fmt.Sprintf("%s@farmer.golang.org", sessionID), ownerID},
|
||||
ValidAfter: uint64(time.Now().Unix()),
|
||||
ValidBefore: uint64(time.Now().Add(d).Unix()),
|
||||
Permissions: ssh.Permissions{
|
||||
Extensions: map[string]string{
|
||||
"permit-X11-forwarding": "",
|
||||
"permit-agent-forwarding": "",
|
||||
"permit-port-forwarding": "",
|
||||
"permit-pty": "",
|
||||
"permit-user-rc": "",
|
||||
},
|
||||
},
|
||||
}
|
||||
if err := cert.SignCert(rand.Reader, caPriKey); err != nil {
|
||||
return nil, fmt.Errorf("cerificate.SignCert() = %w", err)
|
||||
}
|
||||
mCert := ssh.MarshalAuthorizedKey(cert)
|
||||
return mCert, nil
|
||||
}
|
||||
|
||||
// SSHKeyPair generates a set of ecdsa256 SSH Keys. The public key is serialized for inclusion in
|
||||
// an OpenSSH authorized_keys file. The private key is PEM encoded.
|
||||
func SSHKeyPair() (privateKey []byte, publicKey []byte, err error) {
|
||||
private, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
public, err := ssh.NewPublicKey(&private.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
publicKey = ssh.MarshalAuthorizedKey(public)
|
||||
priKeyByt, err := x509.MarshalECPrivateKey(private)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("unable to marshal private key=%w", err)
|
||||
}
|
||||
privateKey = pem.EncodeToMemory(&pem.Block{
|
||||
Type: "EC PRIVATE KEY",
|
||||
Bytes: priKeyByt,
|
||||
})
|
||||
return
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package remote
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func TestSignPublicSSHKey(t *testing.T) {
|
||||
signer, err := ssh.ParsePrivateKey([]byte(devCertCAPrivate))
|
||||
if err != nil {
|
||||
t.Fatalf("ssh.ParsePrivateKey() = %s", err)
|
||||
}
|
||||
ownerID := "accounts.google.com:userIDvalue"
|
||||
sessionID := "user-maria-linux-amd64-12"
|
||||
gotPubKey, err := SignPublicSSHKey(context.Background(), signer, []byte(devCertClientPublic), sessionID, ownerID, time.Minute)
|
||||
if err != nil {
|
||||
t.Fatalf("SignPublicSSHKey(...) = _, %s; want no error", err)
|
||||
}
|
||||
pubKey, _, _, _, err := ssh.ParseAuthorizedKey(gotPubKey)
|
||||
if err != nil {
|
||||
t.Fatalf("ssh.ParseAuthorizedKey(...) = %s; want no error", err)
|
||||
}
|
||||
certChecker := &ssh.CertChecker{}
|
||||
wantPrinciple := fmt.Sprintf("%s@farmer.golang.org", sessionID)
|
||||
pubKeyCert := pubKey.(*ssh.Certificate)
|
||||
if err := certChecker.CheckCert(wantPrinciple, pubKeyCert); err != nil {
|
||||
t.Fatalf("certChecker.CheckCert(%s, %+v) = %s", wantPrinciple, pubKeyCert, err)
|
||||
}
|
||||
if diff := cmp.Diff(pubKeyCert.SignatureKey.Marshal(), signer.PublicKey().Marshal()); diff != "" {
|
||||
t.Fatalf("Public Keys mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// devCertCAPrivate is a private SSH CA certificate to be used for development.
|
||||
devCertCAPrivate = `-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACCVd2FJ3Db/oV53iRDt1RLscTn41hYXbunuCWIlXze2WAAAAJhjy3ePY8t3
|
||||
jwAAAAtzc2gtZWQyNTUxOQAAACCVd2FJ3Db/oV53iRDt1RLscTn41hYXbunuCWIlXze2WA
|
||||
AAAEALuUJMb/rEaFNa+vn5RejeoBiiViyda7djgEvMnQ8fRJV3YUncNv+hXneJEO3VEuxx
|
||||
OfjWFhdu6e4JYiVfN7ZYAAAAE3Rlc3R1c2VyQGdvbGFuZy5vcmcBAg==
|
||||
-----END OPENSSH PRIVATE KEY-----`
|
||||
|
||||
// devCertCAPublic is a public SSH CA certificate to be used for development.
|
||||
devCertCAPublic = `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJV3YUncNv+hXneJEO3VEuxxOfjWFhdu6e4JYiVfN7ZY testuser@golang.org`
|
||||
|
||||
// devCertClientPrivate is a private SSH certificate to be used for development.
|
||||
devCertClientPrivate = `-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACBxCM6ADdHnjTIHG/IpMa3z32CLwtu3BDUR3k2NNbI3owAAAKDFZ7xtxWe8
|
||||
bQAAAAtzc2gtZWQyNTUxOQAAACBxCM6ADdHnjTIHG/IpMa3z32CLwtu3BDUR3k2NNbI3ow
|
||||
AAAECidrOyYbTlYxyBSPP7W/UHk3Si2dgWSfkT+eEIETcvqHEIzoAN0eeNMgcb8ikxrfPf
|
||||
YIvC27cENRHeTY01sjejAAAAFnRlc3RfY2xpZW50QGdvbGFuZy5vcmcBAgMEBQYH
|
||||
-----END OPENSSH PRIVATE KEY-----`
|
||||
|
||||
// devCertClientPublic is a public SSH certificate to be used for development.
|
||||
devCertClientPublic = `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHEIzoAN0eeNMgcb8ikxrfPfYIvC27cENRHeTY01sjej test_client@golang.org`
|
||||
|
||||
// devCertAlternateClientPrivate is a private SSH certificate to be used for development.
|
||||
devCertAlternateClientPrivate = `-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACDOj8K2lbCSv+LojNcrUf0XH1vqknuEZBkAceiBHuNuEQAAAKDYNRtZ2DUb
|
||||
WQAAAAtzc2gtZWQyNTUxOQAAACDOj8K2lbCSv+LojNcrUf0XH1vqknuEZBkAceiBHuNuEQ
|
||||
AAAEDS4G3tQt5S4v7CD+DVyT/mwOKgIScIgFOpFt/EsCXL9M6PwraVsJK/4uiM1ytR/Rcf
|
||||
W+qSe4RkGQBx6IEe424RAAAAF3Rlc3RfZGlzY2FyZEBnb2xhbmcub3JnAQIDBAUG
|
||||
-----END OPENSSH PRIVATE KEY-----`
|
||||
|
||||
// devCertAlternateClientPublic is a public SSH to be used for development.
|
||||
devCertAlternateClientPublic = `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIM6PwraVsJK/4uiM1ytR/RcfW+qSe4RkGQBx6IEe424R test_discard@golang.org`
|
||||
)
|
|
@ -23,6 +23,7 @@ import (
|
|||
"golang.org/x/build/internal/coordinator/schedule"
|
||||
"golang.org/x/build/internal/gomote/protos"
|
||||
"golang.org/x/build/types"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
@ -38,15 +39,21 @@ type Server struct {
|
|||
// embed the unimplemented server.
|
||||
protos.UnimplementedGomoteServiceServer
|
||||
|
||||
buildlets *remote.SessionPool
|
||||
scheduler scheduler
|
||||
buildlets *remote.SessionPool
|
||||
scheduler scheduler
|
||||
sshCertificateAuthority ssh.Signer
|
||||
}
|
||||
|
||||
// New creates a gomote server.
|
||||
func New(rsp *remote.SessionPool, sched *schedule.Scheduler) *Server {
|
||||
// New creates a gomote server. If the rawCAPriKey is invalid, the program will exit.
|
||||
func New(rsp *remote.SessionPool, sched *schedule.Scheduler, rawCAPriKey []byte) *Server {
|
||||
signer, err := ssh.ParsePrivateKey(rawCAPriKey)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to parse raw certificate authority private key into signer=%s", err)
|
||||
}
|
||||
return &Server{
|
||||
buildlets: rsp,
|
||||
scheduler: sched,
|
||||
buildlets: rsp,
|
||||
scheduler: sched,
|
||||
sshCertificateAuthority: signer,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,6 +168,7 @@ func (s *Server) InstanceAlive(ctx context.Context, req *protos.InstanceAliveReq
|
|||
return &protos.InstanceAliveResponse{}, nil
|
||||
}
|
||||
|
||||
// ListDirectory lists the contents of the directory on a gomote instance.
|
||||
func (s *Server) ListDirectory(ctx context.Context, req *protos.ListDirectoryRequest) (*protos.ListDirectoryResponse, error) {
|
||||
creds, err := access.IAPFromContext(ctx)
|
||||
if err != nil {
|
||||
|
@ -306,6 +314,28 @@ func (s *Server) RemoveFiles(ctx context.Context, req *protos.RemoveFilesRequest
|
|||
return &protos.RemoveFilesResponse{}, nil
|
||||
}
|
||||
|
||||
// SignSSHKey signs the public SSH key with a certificate. The signed public SSH key is intended for use with the gomote service SSH
|
||||
// server. It will be signed by the certificate authority of the server and will restrict access to the gomote instance that it was
|
||||
// signed for.
|
||||
func (s *Server) SignSSHKey(ctx context.Context, req *protos.SignSSHKeyRequest) (*protos.SignSSHKeyResponse, error) {
|
||||
creds, err := access.IAPFromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "request does not contain the required authentication")
|
||||
}
|
||||
session, err := s.session(req.GetGomoteId(), creds.ID)
|
||||
if err != nil {
|
||||
// the helper function returns meaningful GRPC error.
|
||||
return nil, err
|
||||
}
|
||||
signedPublicKey, err := remote.SignPublicSSHKey(ctx, s.sshCertificateAuthority, req.GetPublicSshKey(), session.ID, session.OwnerID, 5*time.Minute)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "unable to sign ssh key")
|
||||
}
|
||||
return &protos.SignSSHKeyResponse{
|
||||
SignedPublicSshKey: signedPublicKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WriteTGZFromURL will instruct the gomote instance to download the tar.gz from the provided URL. The tar.gz file will be unpacked in the work directory
|
||||
// relative to the directory provided.
|
||||
func (s *Server) WriteTGZFromURL(ctx context.Context, req *protos.WriteTGZFromURLRequest) (*protos.WriteTGZFromURLResponse, error) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"golang.org/x/build/internal/coordinator/remote"
|
||||
"golang.org/x/build/internal/coordinator/schedule"
|
||||
"golang.org/x/build/internal/gomote/protos"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"golang.org/x/net/nettest"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
|
@ -26,10 +27,15 @@ import (
|
|||
"google.golang.org/protobuf/testing/protocmp"
|
||||
)
|
||||
|
||||
func fakeGomoteServer(ctx context.Context) protos.GomoteServiceServer {
|
||||
func fakeGomoteServer(t *testing.T, ctx context.Context) protos.GomoteServiceServer {
|
||||
signer, err := ssh.ParsePrivateKey([]byte(devCertCAPrivate))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to parse raw certificate authority private key into signer=%s", err)
|
||||
}
|
||||
return &Server{
|
||||
buildlets: remote.NewSessionPool(ctx),
|
||||
scheduler: schedule.NewFake(),
|
||||
buildlets: remote.NewSessionPool(ctx),
|
||||
scheduler: schedule.NewFake(),
|
||||
sshCertificateAuthority: signer,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +46,7 @@ func setupGomoteTest(t *testing.T, ctx context.Context) protos.GomoteServiceClie
|
|||
}
|
||||
sopts := access.FakeIAPAuthInterceptorOptions()
|
||||
s := grpc.NewServer(sopts...)
|
||||
protos.RegisterGomoteServiceServer(s, fakeGomoteServer(ctx))
|
||||
protos.RegisterGomoteServiceServer(s, fakeGomoteServer(t, ctx))
|
||||
go s.Serve(lis)
|
||||
|
||||
// create GRPC client
|
||||
|
@ -149,7 +155,7 @@ func TestCreateInstanceError(t *testing.T) {
|
|||
t.Fatal("stream.Recv = stream, io.EOF; want no EOF")
|
||||
}
|
||||
if got != nil && status.Code(got) != tc.wantCode {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
t.Fatalf("unexpected error: %s; want %s", err, tc.wantCode)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -172,7 +178,7 @@ func TestInstanceAlive(t *testing.T) {
|
|||
|
||||
func TestInstanceAliveError(t *testing.T) {
|
||||
// This test will create a gomote instance and attempt to call InstanceAlive.
|
||||
// If overrideID is set to true, the test will use a diffrent gomoteID than the
|
||||
// If overrideID is set to true, the test will use a different gomoteID than the
|
||||
// the one created for the test.
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -217,7 +223,7 @@ func TestInstanceAliveError(t *testing.T) {
|
|||
}
|
||||
got, err := client.InstanceAlive(tc.ctx, req)
|
||||
if err != nil && status.Code(err) != tc.wantCode {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
t.Fatalf("unexpected error: %s; want %s", err, tc.wantCode)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("client.InstanceAlive(ctx, %v) = %v, nil; want error", req, got)
|
||||
|
@ -240,7 +246,7 @@ func TestListDirectory(t *testing.T) {
|
|||
|
||||
func TestListDirectoryError(t *testing.T) {
|
||||
// This test will create a gomote instance and attempt to call ListDirectory.
|
||||
// If overrideID is set to true, the test will use a diffrent gomoteID than the
|
||||
// If overrideID is set to true, the test will use a different gomoteID than the
|
||||
// the one created for the test.
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -302,7 +308,7 @@ func TestListDirectoryError(t *testing.T) {
|
|||
}
|
||||
got, err := client.ListDirectory(tc.ctx, req)
|
||||
if err != nil && status.Code(err) != tc.wantCode {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
t.Fatalf("unexpected error: %s; want %s", err, tc.wantCode)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("client.RemoveFiles(ctx, %v) = %v, nil; want error", req, got)
|
||||
|
@ -345,7 +351,7 @@ func TestDestroyInstance(t *testing.T) {
|
|||
|
||||
func TestDestroyInstanceError(t *testing.T) {
|
||||
// This test will create a gomote instance and attempt to call DestroyInstance.
|
||||
// If overrideID is set to true, the test will use a diffrent gomoteID than the
|
||||
// If overrideID is set to true, the test will use a different gomoteID than the
|
||||
// the one created for the test.
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -392,7 +398,7 @@ func TestDestroyInstanceError(t *testing.T) {
|
|||
}
|
||||
got, err := client.DestroyInstance(tc.ctx, req)
|
||||
if err != nil && status.Code(err) != tc.wantCode {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
t.Fatalf("unexpected error: %s; want %s", err, tc.wantCode)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("client.DestroyInstance(ctx, %v) = %v, nil; want error", req, got)
|
||||
|
@ -524,7 +530,7 @@ func TestRemoveFiles(t *testing.T) {
|
|||
|
||||
func TestRemoveFilesError(t *testing.T) {
|
||||
// This test will create a gomote instance and attempt to call RemoveFiles.
|
||||
// If overrideID is set to true, the test will use a diffrent gomoteID than the
|
||||
// If overrideID is set to true, the test will use a different gomoteID than the
|
||||
// the one created for the test.
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -581,7 +587,7 @@ func TestRemoveFilesError(t *testing.T) {
|
|||
}
|
||||
got, err := client.RemoveFiles(tc.ctx, req)
|
||||
if err != nil && status.Code(err) != tc.wantCode {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
t.Fatalf("unexpected error: %s; want %s", err, tc.wantCode)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("client.RemoveFiles(ctx, %v) = %v, nil; want error", req, got)
|
||||
|
@ -590,6 +596,85 @@ func TestRemoveFilesError(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSignSSHKey(t *testing.T) {
|
||||
ctx := access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP())
|
||||
client := setupGomoteTest(t, context.Background())
|
||||
gomoteID := mustCreateInstance(t, client, fakeIAP())
|
||||
if _, err := client.SignSSHKey(ctx, &protos.SignSSHKeyRequest{
|
||||
GomoteId: gomoteID,
|
||||
PublicSshKey: []byte(devCertCAPublic),
|
||||
}); err != nil {
|
||||
t.Fatalf("client.SignSSHKey(ctx, req) = response, %s; want no error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignSSHKeyError(t *testing.T) {
|
||||
// This test will create a gomote instance and attempt to call SignSSHKey.
|
||||
// If overrideID is set to true, the test will use a different gomoteID than the
|
||||
// the one created for the test.
|
||||
testCases := []struct {
|
||||
desc string
|
||||
ctx context.Context
|
||||
overrideID bool
|
||||
gomoteID string // Used iff overrideID is true.
|
||||
publickSSHKey []byte
|
||||
wantCode codes.Code
|
||||
}{
|
||||
{
|
||||
desc: "unauthenticated request",
|
||||
ctx: context.Background(),
|
||||
wantCode: codes.Unauthenticated,
|
||||
},
|
||||
{
|
||||
desc: "missing gomote id",
|
||||
ctx: access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP()),
|
||||
overrideID: true,
|
||||
gomoteID: "",
|
||||
wantCode: codes.NotFound,
|
||||
},
|
||||
{
|
||||
desc: "missing public key",
|
||||
ctx: access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP()),
|
||||
wantCode: codes.InvalidArgument,
|
||||
},
|
||||
{
|
||||
desc: "gomote does not exist",
|
||||
ctx: access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAPWithUser("foo", "bar")),
|
||||
overrideID: true,
|
||||
gomoteID: "chucky",
|
||||
publickSSHKey: []byte(devCertCAPublic),
|
||||
wantCode: codes.NotFound,
|
||||
},
|
||||
{
|
||||
desc: "wrong gomote id",
|
||||
ctx: access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAPWithUser("foo", "bar")),
|
||||
overrideID: false,
|
||||
publickSSHKey: []byte(devCertCAPublic),
|
||||
wantCode: codes.PermissionDenied,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
client := setupGomoteTest(t, context.Background())
|
||||
gomoteID := mustCreateInstance(t, client, fakeIAP())
|
||||
if tc.overrideID {
|
||||
gomoteID = tc.gomoteID
|
||||
}
|
||||
req := &protos.SignSSHKeyRequest{
|
||||
GomoteId: gomoteID,
|
||||
PublicSshKey: tc.publickSSHKey,
|
||||
}
|
||||
got, err := client.SignSSHKey(tc.ctx, req)
|
||||
if err != nil && status.Code(err) != tc.wantCode {
|
||||
t.Fatalf("unexpected error: %s; want %s", err, tc.wantCode)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("client.SignSSHKey(ctx, %v) = %v, nil; want error", req, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteTGZFromURL(t *testing.T) {
|
||||
ctx := access.FakeContextWithOutgoingIAPAuth(context.Background(), fakeIAP())
|
||||
client := setupGomoteTest(t, context.Background())
|
||||
|
@ -605,7 +690,7 @@ func TestWriteTGZFromURL(t *testing.T) {
|
|||
|
||||
func TestWriteTGZFromURLError(t *testing.T) {
|
||||
// This test will create a gomote instance and attempt to call TestWriteTGZFromURL.
|
||||
// If overrideID is set to true, the test will use a diffrent gomoteID than the
|
||||
// If overrideID is set to true, the test will use a different gomoteID than the
|
||||
// the one created for the test.
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
@ -663,7 +748,7 @@ func TestWriteTGZFromURLError(t *testing.T) {
|
|||
}
|
||||
got, err := client.WriteTGZFromURL(tc.ctx, req)
|
||||
if err != nil && status.Code(err) != tc.wantCode {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
t.Fatalf("unexpected error: %s; want %s", err, tc.wantCode)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("client.WriteTGZFromURL(ctx, %v) = %v, nil; want error", req, got)
|
||||
|
@ -772,3 +857,17 @@ func mustCreateInstance(t *testing.T, client protos.GomoteServiceClient, iap acc
|
|||
}
|
||||
return gomoteID
|
||||
}
|
||||
|
||||
const (
|
||||
// devCertCAPrivate is a private SSH CA certificate to be used for development.
|
||||
devCertCAPrivate = `-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACCVd2FJ3Db/oV53iRDt1RLscTn41hYXbunuCWIlXze2WAAAAJhjy3ePY8t3
|
||||
jwAAAAtzc2gtZWQyNTUxOQAAACCVd2FJ3Db/oV53iRDt1RLscTn41hYXbunuCWIlXze2WA
|
||||
AAAEALuUJMb/rEaFNa+vn5RejeoBiiViyda7djgEvMnQ8fRJV3YUncNv+hXneJEO3VEuxx
|
||||
OfjWFhdu6e4JYiVfN7ZYAAAAE3Rlc3R1c2VyQGdvbGFuZy5vcmcBAg==
|
||||
-----END OPENSSH PRIVATE KEY-----`
|
||||
|
||||
// devCertCAPublic is a public SSH CA certificate to be used for development.
|
||||
devCertCAPublic = `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJV3YUncNv+hXneJEO3VEuxxOfjWFhdu6e4JYiVfN7ZY testuser@golang.org`
|
||||
)
|
||||
|
|
|
@ -1086,15 +1086,20 @@ func (*RemoveFilesResponse) Descriptor() ([]byte, []int) {
|
|||
return file_gomote_proto_rawDescGZIP(), []int{18}
|
||||
}
|
||||
|
||||
// RetrieveSSHCredentialsRequest specifies the data needed to retrieve SSH credentials for a gomote instance.
|
||||
type RetrieveSSHCredentialsRequest struct {
|
||||
// SignSSHKeyRequest specifies the data needed to sign a public SSH key which attaches a certificate to the key.
|
||||
type SignSSHKeyRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The unique identifier for a gomote instance.
|
||||
GomoteId string `protobuf:"bytes,1,opt,name=gomote_id,json=gomoteId,proto3" json:"gomote_id,omitempty"`
|
||||
// A user provided public SSH key which the user intends to initiate an SSH session with.
|
||||
PublicSshKey []byte `protobuf:"bytes,2,opt,name=public_ssh_key,json=publicSshKey,proto3" json:"public_ssh_key,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RetrieveSSHCredentialsRequest) Reset() {
|
||||
*x = RetrieveSSHCredentialsRequest{}
|
||||
func (x *SignSSHKeyRequest) Reset() {
|
||||
*x = SignSSHKeyRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_gomote_proto_msgTypes[19]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
|
@ -1102,13 +1107,13 @@ func (x *RetrieveSSHCredentialsRequest) Reset() {
|
|||
}
|
||||
}
|
||||
|
||||
func (x *RetrieveSSHCredentialsRequest) String() string {
|
||||
func (x *SignSSHKeyRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RetrieveSSHCredentialsRequest) ProtoMessage() {}
|
||||
func (*SignSSHKeyRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RetrieveSSHCredentialsRequest) ProtoReflect() protoreflect.Message {
|
||||
func (x *SignSSHKeyRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_gomote_proto_msgTypes[19]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
|
@ -1120,20 +1125,38 @@ func (x *RetrieveSSHCredentialsRequest) ProtoReflect() protoreflect.Message {
|
|||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RetrieveSSHCredentialsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RetrieveSSHCredentialsRequest) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use SignSSHKeyRequest.ProtoReflect.Descriptor instead.
|
||||
func (*SignSSHKeyRequest) Descriptor() ([]byte, []int) {
|
||||
return file_gomote_proto_rawDescGZIP(), []int{19}
|
||||
}
|
||||
|
||||
// RetrieveSSHCredentialsResponse contains SSH credentials for a gomote instance.
|
||||
type RetrieveSSHCredentialsResponse struct {
|
||||
func (x *SignSSHKeyRequest) GetGomoteId() string {
|
||||
if x != nil {
|
||||
return x.GomoteId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SignSSHKeyRequest) GetPublicSshKey() []byte {
|
||||
if x != nil {
|
||||
return x.PublicSshKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SignSSHKeyResponse contains the results from a request to sign a public SSH key.
|
||||
type SignSSHKeyResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// A signed SSH key can be used in conjunction with the associated private key to initiate an SSH session to a gomote instance.
|
||||
// The certificate attached to the key will contain principles which restrict the instance that can be logged into.
|
||||
SignedPublicSshKey []byte `protobuf:"bytes,1,opt,name=signed_public_ssh_key,json=signedPublicSshKey,proto3" json:"signed_public_ssh_key,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RetrieveSSHCredentialsResponse) Reset() {
|
||||
*x = RetrieveSSHCredentialsResponse{}
|
||||
func (x *SignSSHKeyResponse) Reset() {
|
||||
*x = SignSSHKeyResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_gomote_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
|
@ -1141,13 +1164,13 @@ func (x *RetrieveSSHCredentialsResponse) Reset() {
|
|||
}
|
||||
}
|
||||
|
||||
func (x *RetrieveSSHCredentialsResponse) String() string {
|
||||
func (x *SignSSHKeyResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RetrieveSSHCredentialsResponse) ProtoMessage() {}
|
||||
func (*SignSSHKeyResponse) ProtoMessage() {}
|
||||
|
||||
func (x *RetrieveSSHCredentialsResponse) ProtoReflect() protoreflect.Message {
|
||||
func (x *SignSSHKeyResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_gomote_proto_msgTypes[20]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
|
@ -1159,11 +1182,18 @@ func (x *RetrieveSSHCredentialsResponse) ProtoReflect() protoreflect.Message {
|
|||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RetrieveSSHCredentialsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*RetrieveSSHCredentialsResponse) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use SignSSHKeyResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SignSSHKeyResponse) Descriptor() ([]byte, []int) {
|
||||
return file_gomote_proto_rawDescGZIP(), []int{20}
|
||||
}
|
||||
|
||||
func (x *SignSSHKeyResponse) GetSignedPublicSshKey() []byte {
|
||||
if x != nil {
|
||||
return x.SignedPublicSshKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteTGZRequest specifies the data needed to expand a tar and zipped file onto the file system of a gomote instance.
|
||||
type WriteTGZRequest struct {
|
||||
state protoimpl.MessageState
|
||||
|
@ -1439,87 +1469,90 @@ var file_gomote_proto_rawDesc = []byte{
|
|||
0x52, 0x08, 0x67, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61,
|
||||
0x74, 0x68, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73,
|
||||
0x22, 0x15, 0x0a, 0x13, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x0a, 0x1d, 0x52, 0x65, 0x74, 0x72, 0x69,
|
||||
0x65, 0x76, 0x65, 0x53, 0x53, 0x48, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x20, 0x0a, 0x1e, 0x52, 0x65, 0x74, 0x72,
|
||||
0x69, 0x65, 0x76, 0x65, 0x53, 0x53, 0x48, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x0a, 0x0f, 0x57, 0x72,
|
||||
0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a,
|
||||
0x10, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x65, 0x0a, 0x16, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x46, 0x72, 0x6f,
|
||||
0x6d, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x67,
|
||||
0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x67, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69,
|
||||
0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64,
|
||||
0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x19, 0x0a, 0x17, 0x57, 0x72, 0x69, 0x74,
|
||||
0x65, 0x54, 0x47, 0x5a, 0x46, 0x72, 0x6f, 0x6d, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x32, 0xda, 0x07, 0x0a, 0x0d, 0x47, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41,
|
||||
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x12, 0x53, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x73, 0x74,
|
||||
0x61, 0x6e, 0x63, 0x65, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x43, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x54, 0x0a, 0x0f, 0x44, 0x65, 0x73, 0x74, 0x72,
|
||||
0x6f, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x73, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x53, 0x0a,
|
||||
0x0e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12,
|
||||
0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65,
|
||||
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x43,
|
||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x30, 0x01, 0x12, 0x4e, 0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x6c,
|
||||
0x69, 0x76, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x73,
|
||||
0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74,
|
||||
0x6f, 0x72, 0x79, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44,
|
||||
0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x12, 0x4e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x12, 0x3e, 0x0a, 0x07, 0x52, 0x65, 0x61, 0x64, 0x54, 0x47, 0x5a, 0x12, 0x16, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x54, 0x47, 0x5a, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52,
|
||||
0x65, 0x61, 0x64, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x30, 0x01, 0x12, 0x48, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65,
|
||||
0x73, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76,
|
||||
0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x69, 0x0a, 0x16,
|
||||
0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x53, 0x53, 0x48, 0x43, 0x72, 0x65, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
|
||||
0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x53, 0x53, 0x48, 0x43, 0x72, 0x65, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x53,
|
||||
0x53, 0x48, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x08, 0x57, 0x72, 0x69, 0x74, 0x65,
|
||||
0x54, 0x47, 0x5a, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x57, 0x72, 0x69,
|
||||
0x74, 0x65, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x12, 0x54, 0x0a, 0x0f, 0x57, 0x72,
|
||||
0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x46, 0x72, 0x6f, 0x6d, 0x55, 0x52, 0x4c, 0x12, 0x1e, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x46,
|
||||
0x72, 0x6f, 0x6d, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x46,
|
||||
0x72, 0x6f, 0x6d, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x42, 0x2b, 0x5a, 0x29, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78,
|
||||
0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
||||
0x67, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x56, 0x0a, 0x11, 0x53, 0x69, 0x67, 0x6e, 0x53,
|
||||
0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x67, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x67, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x70, 0x75, 0x62,
|
||||
0x6c, 0x69, 0x63, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x0c, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x22,
|
||||
0x47, 0x0a, 0x12, 0x53, 0x69, 0x67, 0x6e, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x15, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f,
|
||||
0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x73, 0x73, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x50, 0x75, 0x62, 0x6c,
|
||||
0x69, 0x63, 0x53, 0x73, 0x68, 0x4b, 0x65, 0x79, 0x22, 0x11, 0x0a, 0x0f, 0x57, 0x72, 0x69, 0x74,
|
||||
0x65, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x12, 0x0a, 0x10, 0x57,
|
||||
0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x65, 0x0a, 0x16, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x46, 0x72, 0x6f, 0x6d, 0x55,
|
||||
0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x6f, 0x6d,
|
||||
0x6f, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x67, 0x6f,
|
||||
0x6d, 0x6f, 0x74, 0x65, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65,
|
||||
0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72,
|
||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x22, 0x19, 0x0a, 0x17, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54,
|
||||
0x47, 0x5a, 0x46, 0x72, 0x6f, 0x6d, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x32, 0xb6, 0x07, 0x0a, 0x0d, 0x47, 0x6f, 0x6d, 0x6f, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x75, 0x74,
|
||||
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x12, 0x53, 0x0a, 0x0e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e,
|
||||
0x63, 0x65, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x54, 0x0a, 0x0f, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79,
|
||||
0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x73, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x73, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x53, 0x0a, 0x0e, 0x45,
|
||||
0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x1d, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x43, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x65, 0x43, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01,
|
||||
0x12, 0x4e, 0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x6c, 0x69, 0x76,
|
||||
0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61,
|
||||
0x6e, 0x63, 0x65, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x12, 0x4e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72,
|
||||
0x79, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44,
|
||||
0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x69, 0x72,
|
||||
0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x12, 0x4e, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x73, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x73,
|
||||
0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||
0x12, 0x3e, 0x0a, 0x07, 0x52, 0x65, 0x61, 0x64, 0x54, 0x47, 0x5a, 0x12, 0x16, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x65, 0x61,
|
||||
0x64, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01,
|
||||
0x12, 0x48, 0x0a, 0x0b, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12,
|
||||
0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x46,
|
||||
0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x45, 0x0a, 0x0a, 0x53, 0x69,
|
||||
0x67, 0x6e, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x73, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x53, 0x69, 0x67,
|
||||
0x6e, 0x53, 0x53, 0x48, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||
0x00, 0x12, 0x41, 0x0a, 0x08, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x12, 0x17, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2e,
|
||||
0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x28, 0x01, 0x12, 0x54, 0x0a, 0x0f, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a,
|
||||
0x46, 0x72, 0x6f, 0x6d, 0x55, 0x52, 0x4c, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
|
||||
0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x46, 0x72, 0x6f, 0x6d, 0x55, 0x52, 0x4c,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73,
|
||||
0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x54, 0x47, 0x5a, 0x46, 0x72, 0x6f, 0x6d, 0x55, 0x52, 0x4c,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x6f,
|
||||
0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x78, 0x2f, 0x62, 0x75, 0x69, 0x6c, 0x64,
|
||||
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x6f, 0x6d, 0x6f, 0x74, 0x65,
|
||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -1537,32 +1570,32 @@ func file_gomote_proto_rawDescGZIP() []byte {
|
|||
var file_gomote_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_gomote_proto_msgTypes = make([]protoimpl.MessageInfo, 25)
|
||||
var file_gomote_proto_goTypes = []interface{}{
|
||||
(CreateInstanceResponse_Status)(0), // 0: protos.CreateInstanceResponse.Status
|
||||
(*AuthenticateRequest)(nil), // 1: protos.AuthenticateRequest
|
||||
(*AuthenticateResponse)(nil), // 2: protos.AuthenticateResponse
|
||||
(*CreateInstanceRequest)(nil), // 3: protos.CreateInstanceRequest
|
||||
(*CreateInstanceResponse)(nil), // 4: protos.CreateInstanceResponse
|
||||
(*DestroyInstanceRequest)(nil), // 5: protos.DestroyInstanceRequest
|
||||
(*DestroyInstanceResponse)(nil), // 6: protos.DestroyInstanceResponse
|
||||
(*ExecuteCommandRequest)(nil), // 7: protos.ExecuteCommandRequest
|
||||
(*ExecuteCommandResponse)(nil), // 8: protos.ExecuteCommandResponse
|
||||
(*Instance)(nil), // 9: protos.Instance
|
||||
(*InstanceAliveRequest)(nil), // 10: protos.InstanceAliveRequest
|
||||
(*InstanceAliveResponse)(nil), // 11: protos.InstanceAliveResponse
|
||||
(*ListDirectoryRequest)(nil), // 12: protos.ListDirectoryRequest
|
||||
(*ListDirectoryResponse)(nil), // 13: protos.ListDirectoryResponse
|
||||
(*ListInstancesRequest)(nil), // 14: protos.ListInstancesRequest
|
||||
(*ListInstancesResponse)(nil), // 15: protos.ListInstancesResponse
|
||||
(*ReadTGZRequest)(nil), // 16: protos.ReadTGZRequest
|
||||
(*ReadTGZResponse)(nil), // 17: protos.ReadTGZResponse
|
||||
(*RemoveFilesRequest)(nil), // 18: protos.RemoveFilesRequest
|
||||
(*RemoveFilesResponse)(nil), // 19: protos.RemoveFilesResponse
|
||||
(*RetrieveSSHCredentialsRequest)(nil), // 20: protos.RetrieveSSHCredentialsRequest
|
||||
(*RetrieveSSHCredentialsResponse)(nil), // 21: protos.RetrieveSSHCredentialsResponse
|
||||
(*WriteTGZRequest)(nil), // 22: protos.WriteTGZRequest
|
||||
(*WriteTGZResponse)(nil), // 23: protos.WriteTGZResponse
|
||||
(*WriteTGZFromURLRequest)(nil), // 24: protos.WriteTGZFromURLRequest
|
||||
(*WriteTGZFromURLResponse)(nil), // 25: protos.WriteTGZFromURLResponse
|
||||
(CreateInstanceResponse_Status)(0), // 0: protos.CreateInstanceResponse.Status
|
||||
(*AuthenticateRequest)(nil), // 1: protos.AuthenticateRequest
|
||||
(*AuthenticateResponse)(nil), // 2: protos.AuthenticateResponse
|
||||
(*CreateInstanceRequest)(nil), // 3: protos.CreateInstanceRequest
|
||||
(*CreateInstanceResponse)(nil), // 4: protos.CreateInstanceResponse
|
||||
(*DestroyInstanceRequest)(nil), // 5: protos.DestroyInstanceRequest
|
||||
(*DestroyInstanceResponse)(nil), // 6: protos.DestroyInstanceResponse
|
||||
(*ExecuteCommandRequest)(nil), // 7: protos.ExecuteCommandRequest
|
||||
(*ExecuteCommandResponse)(nil), // 8: protos.ExecuteCommandResponse
|
||||
(*Instance)(nil), // 9: protos.Instance
|
||||
(*InstanceAliveRequest)(nil), // 10: protos.InstanceAliveRequest
|
||||
(*InstanceAliveResponse)(nil), // 11: protos.InstanceAliveResponse
|
||||
(*ListDirectoryRequest)(nil), // 12: protos.ListDirectoryRequest
|
||||
(*ListDirectoryResponse)(nil), // 13: protos.ListDirectoryResponse
|
||||
(*ListInstancesRequest)(nil), // 14: protos.ListInstancesRequest
|
||||
(*ListInstancesResponse)(nil), // 15: protos.ListInstancesResponse
|
||||
(*ReadTGZRequest)(nil), // 16: protos.ReadTGZRequest
|
||||
(*ReadTGZResponse)(nil), // 17: protos.ReadTGZResponse
|
||||
(*RemoveFilesRequest)(nil), // 18: protos.RemoveFilesRequest
|
||||
(*RemoveFilesResponse)(nil), // 19: protos.RemoveFilesResponse
|
||||
(*SignSSHKeyRequest)(nil), // 20: protos.SignSSHKeyRequest
|
||||
(*SignSSHKeyResponse)(nil), // 21: protos.SignSSHKeyResponse
|
||||
(*WriteTGZRequest)(nil), // 22: protos.WriteTGZRequest
|
||||
(*WriteTGZResponse)(nil), // 23: protos.WriteTGZResponse
|
||||
(*WriteTGZFromURLRequest)(nil), // 24: protos.WriteTGZFromURLRequest
|
||||
(*WriteTGZFromURLResponse)(nil), // 25: protos.WriteTGZFromURLResponse
|
||||
}
|
||||
var file_gomote_proto_depIdxs = []int32{
|
||||
9, // 0: protos.CreateInstanceResponse.instance:type_name -> protos.Instance
|
||||
|
@ -1577,7 +1610,7 @@ var file_gomote_proto_depIdxs = []int32{
|
|||
14, // 9: protos.GomoteService.ListInstances:input_type -> protos.ListInstancesRequest
|
||||
16, // 10: protos.GomoteService.ReadTGZ:input_type -> protos.ReadTGZRequest
|
||||
18, // 11: protos.GomoteService.RemoveFiles:input_type -> protos.RemoveFilesRequest
|
||||
20, // 12: protos.GomoteService.RetrieveSSHCredentials:input_type -> protos.RetrieveSSHCredentialsRequest
|
||||
20, // 12: protos.GomoteService.SignSSHKey:input_type -> protos.SignSSHKeyRequest
|
||||
22, // 13: protos.GomoteService.WriteTGZ:input_type -> protos.WriteTGZRequest
|
||||
24, // 14: protos.GomoteService.WriteTGZFromURL:input_type -> protos.WriteTGZFromURLRequest
|
||||
2, // 15: protos.GomoteService.Authenticate:output_type -> protos.AuthenticateResponse
|
||||
|
@ -1589,7 +1622,7 @@ var file_gomote_proto_depIdxs = []int32{
|
|||
15, // 21: protos.GomoteService.ListInstances:output_type -> protos.ListInstancesResponse
|
||||
17, // 22: protos.GomoteService.ReadTGZ:output_type -> protos.ReadTGZResponse
|
||||
19, // 23: protos.GomoteService.RemoveFiles:output_type -> protos.RemoveFilesResponse
|
||||
21, // 24: protos.GomoteService.RetrieveSSHCredentials:output_type -> protos.RetrieveSSHCredentialsResponse
|
||||
21, // 24: protos.GomoteService.SignSSHKey:output_type -> protos.SignSSHKeyResponse
|
||||
23, // 25: protos.GomoteService.WriteTGZ:output_type -> protos.WriteTGZResponse
|
||||
25, // 26: protos.GomoteService.WriteTGZFromURL:output_type -> protos.WriteTGZFromURLResponse
|
||||
15, // [15:27] is the sub-list for method output_type
|
||||
|
@ -1834,7 +1867,7 @@ func file_gomote_proto_init() {
|
|||
}
|
||||
}
|
||||
file_gomote_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RetrieveSSHCredentialsRequest); i {
|
||||
switch v := v.(*SignSSHKeyRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
|
@ -1846,7 +1879,7 @@ func file_gomote_proto_init() {
|
|||
}
|
||||
}
|
||||
file_gomote_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RetrieveSSHCredentialsResponse); i {
|
||||
switch v := v.(*SignSSHKeyResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
|
|
|
@ -28,8 +28,8 @@ service GomoteService {
|
|||
rpc ReadTGZ (ReadTGZRequest) returns (stream ReadTGZResponse) {}
|
||||
// RemoveFiles removes files or directories from the gomote instance.
|
||||
rpc RemoveFiles (RemoveFilesRequest) returns (RemoveFilesResponse) {}
|
||||
// RetrieveSSHCredentials retrieves the SSH credentials for the specified gomote instance.
|
||||
rpc RetrieveSSHCredentials (RetrieveSSHCredentialsRequest) returns (RetrieveSSHCredentialsResponse) {}
|
||||
// SignSSHKey signs an SSH public key which can be used to SSH into instances owned by the caller.
|
||||
rpc SignSSHKey (SignSSHKeyRequest) returns (SignSSHKeyResponse) {}
|
||||
// WriteTGZ expands a tar and zipped file onto the file system of a gomote instance.
|
||||
rpc WriteTGZ (stream WriteTGZRequest) returns (WriteTGZResponse) {}
|
||||
// WriteTGZFromURL retrieves a tar and zipped file from a URL and expands it onto the file system of a gomote instance.
|
||||
|
@ -174,11 +174,20 @@ message RemoveFilesRequest {
|
|||
// RemoveFilesResponse contains the results from removing files or directories from a gomote instance.
|
||||
message RemoveFilesResponse {}
|
||||
|
||||
// RetrieveSSHCredentialsRequest specifies the data needed to retrieve SSH credentials for a gomote instance.
|
||||
message RetrieveSSHCredentialsRequest {}
|
||||
// SignSSHKeyRequest specifies the data needed to sign a public SSH key which attaches a certificate to the key.
|
||||
message SignSSHKeyRequest {
|
||||
// The unique identifier for a gomote instance.
|
||||
string gomote_id = 1;
|
||||
// A user provided public SSH key which the user intends to initiate an SSH session with.
|
||||
bytes public_ssh_key = 2;
|
||||
}
|
||||
|
||||
// RetrieveSSHCredentialsResponse contains SSH credentials for a gomote instance.
|
||||
message RetrieveSSHCredentialsResponse {}
|
||||
// SignSSHKeyResponse contains the results from a request to sign a public SSH key.
|
||||
message SignSSHKeyResponse {
|
||||
// A signed SSH key can be used in conjunction with the associated private key to initiate an SSH session to a gomote instance.
|
||||
// The certificate attached to the key will contain principles which restrict the instance that can be logged into.
|
||||
bytes signed_public_ssh_key = 1;
|
||||
}
|
||||
|
||||
// WriteTGZRequest specifies the data needed to expand a tar and zipped file onto the file system of a gomote instance.
|
||||
message WriteTGZRequest {}
|
||||
|
|
|
@ -36,8 +36,8 @@ type GomoteServiceClient interface {
|
|||
ReadTGZ(ctx context.Context, in *ReadTGZRequest, opts ...grpc.CallOption) (GomoteService_ReadTGZClient, error)
|
||||
// RemoveFiles removes files or directories from the gomote instance.
|
||||
RemoveFiles(ctx context.Context, in *RemoveFilesRequest, opts ...grpc.CallOption) (*RemoveFilesResponse, error)
|
||||
// RetrieveSSHCredentials retrieves the SSH credentials for the specified gomote instance.
|
||||
RetrieveSSHCredentials(ctx context.Context, in *RetrieveSSHCredentialsRequest, opts ...grpc.CallOption) (*RetrieveSSHCredentialsResponse, error)
|
||||
// SignSSHKey signs an SSH public key which can be used to SSH into instances owned by the caller.
|
||||
SignSSHKey(ctx context.Context, in *SignSSHKeyRequest, opts ...grpc.CallOption) (*SignSSHKeyResponse, error)
|
||||
// WriteTGZ expands a tar and zipped file onto the file system of a gomote instance.
|
||||
WriteTGZ(ctx context.Context, opts ...grpc.CallOption) (GomoteService_WriteTGZClient, error)
|
||||
// WriteTGZFromURL retrieves a tar and zipped file from a URL and expands it onto the file system of a gomote instance.
|
||||
|
@ -202,9 +202,9 @@ func (c *gomoteServiceClient) RemoveFiles(ctx context.Context, in *RemoveFilesRe
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (c *gomoteServiceClient) RetrieveSSHCredentials(ctx context.Context, in *RetrieveSSHCredentialsRequest, opts ...grpc.CallOption) (*RetrieveSSHCredentialsResponse, error) {
|
||||
out := new(RetrieveSSHCredentialsResponse)
|
||||
err := c.cc.Invoke(ctx, "/protos.GomoteService/RetrieveSSHCredentials", in, out, opts...)
|
||||
func (c *gomoteServiceClient) SignSSHKey(ctx context.Context, in *SignSSHKeyRequest, opts ...grpc.CallOption) (*SignSSHKeyResponse, error) {
|
||||
out := new(SignSSHKeyResponse)
|
||||
err := c.cc.Invoke(ctx, "/protos.GomoteService/SignSSHKey", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -276,8 +276,8 @@ type GomoteServiceServer interface {
|
|||
ReadTGZ(*ReadTGZRequest, GomoteService_ReadTGZServer) error
|
||||
// RemoveFiles removes files or directories from the gomote instance.
|
||||
RemoveFiles(context.Context, *RemoveFilesRequest) (*RemoveFilesResponse, error)
|
||||
// RetrieveSSHCredentials retrieves the SSH credentials for the specified gomote instance.
|
||||
RetrieveSSHCredentials(context.Context, *RetrieveSSHCredentialsRequest) (*RetrieveSSHCredentialsResponse, error)
|
||||
// SignSSHKey signs an SSH public key which can be used to SSH into instances owned by the caller.
|
||||
SignSSHKey(context.Context, *SignSSHKeyRequest) (*SignSSHKeyResponse, error)
|
||||
// WriteTGZ expands a tar and zipped file onto the file system of a gomote instance.
|
||||
WriteTGZ(GomoteService_WriteTGZServer) error
|
||||
// WriteTGZFromURL retrieves a tar and zipped file from a URL and expands it onto the file system of a gomote instance.
|
||||
|
@ -316,8 +316,8 @@ func (UnimplementedGomoteServiceServer) ReadTGZ(*ReadTGZRequest, GomoteService_R
|
|||
func (UnimplementedGomoteServiceServer) RemoveFiles(context.Context, *RemoveFilesRequest) (*RemoveFilesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RemoveFiles not implemented")
|
||||
}
|
||||
func (UnimplementedGomoteServiceServer) RetrieveSSHCredentials(context.Context, *RetrieveSSHCredentialsRequest) (*RetrieveSSHCredentialsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method RetrieveSSHCredentials not implemented")
|
||||
func (UnimplementedGomoteServiceServer) SignSSHKey(context.Context, *SignSSHKeyRequest) (*SignSSHKeyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SignSSHKey not implemented")
|
||||
}
|
||||
func (UnimplementedGomoteServiceServer) WriteTGZ(GomoteService_WriteTGZServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method WriteTGZ not implemented")
|
||||
|
@ -509,20 +509,20 @@ func _GomoteService_RemoveFiles_Handler(srv interface{}, ctx context.Context, de
|
|||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GomoteService_RetrieveSSHCredentials_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RetrieveSSHCredentialsRequest)
|
||||
func _GomoteService_SignSSHKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SignSSHKeyRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GomoteServiceServer).RetrieveSSHCredentials(ctx, in)
|
||||
return srv.(GomoteServiceServer).SignSSHKey(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/protos.GomoteService/RetrieveSSHCredentials",
|
||||
FullMethod: "/protos.GomoteService/SignSSHKey",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GomoteServiceServer).RetrieveSSHCredentials(ctx, req.(*RetrieveSSHCredentialsRequest))
|
||||
return srv.(GomoteServiceServer).SignSSHKey(ctx, req.(*SignSSHKeyRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
@ -603,8 +603,8 @@ var GomoteService_ServiceDesc = grpc.ServiceDesc{
|
|||
Handler: _GomoteService_RemoveFiles_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RetrieveSSHCredentials",
|
||||
Handler: _GomoteService_RetrieveSSHCredentials_Handler,
|
||||
MethodName: "SignSSHKey",
|
||||
Handler: _GomoteService_SignSSHKey_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "WriteTGZFromURL",
|
||||
|
|
Загрузка…
Ссылка в новой задаче