[feat] pull/push over https - done (#47)

* pull/push impl done

* Basic auth for harness
jobatzil/rename
Enver Bisevac 2022-11-01 19:02:29 +01:00 committed by GitHub
parent 3f7fc109d0
commit fb0e93394d
21 changed files with 1369 additions and 44 deletions

View File

@ -37,6 +37,10 @@ mocks: $(mocks)
wire: cli/server/harness.wire_gen.go cli/server/standalone.wire_gen.go
force-wire:
@sh ./scripts/wire/standalone.sh
@sh ./scripts/wire/harness.sh
generate: $(mocks) wire mocks/mock_client.go proto
@echo "Generating Code"
@ -121,18 +125,10 @@ lint: tools generate # lint the golang code
# the source file has changed.
###########################################
cli/server/harness.wire_gen.go: cli/server/harness.wire.go ## Update the wire dependency injection if harness.wire.go has changed.
@echo "Updating harness.wire_gen.go"
@go run github.com/google/wire/cmd/wire gen -tags=harness -output_file_prefix="harness." github.com/harness/gitness/cli/server
@perl -ni -e 'print unless /go:generate/' cli/server/harness.wire_gen.go
@perl -i -pe's/\+build !wireinject/\+build !wireinject,harness/g' cli/server/harness.wire_gen.go
@perl -i -pe's/go:build !wireinject/go:build !wireinject && harness/g' cli/server/harness.wire_gen.go
cli/server/standalone.wire_gen.go: cli/server/standalone.wire.go ## Update the wire dependency injection if standalone.wire.go has changed.
@echo "Updating standalone.wire_gen.go"
@go run github.com/google/wire/cmd/wire gen -tags= -output_file_prefix="standalone." github.com/harness/gitness/cli/server
@perl -ni -e 'print unless /go:generate/' cli/server/standalone.wire_gen.go
@perl -i -pe's/\+build !wireinject/\+build !wireinject,!harness/g' cli/server/standalone.wire_gen.go
@perl -i -pe's/go:build !wireinject/go:build !wireinject && !harness/g' cli/server/standalone.wire_gen.go
@sh ./scripts/wire/standalone.sh
mocks/mock_client.go: internal/store/store.go client/client.go
go generate mocks/mock.go

View File

@ -85,7 +85,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
}
repoController := repo.ProvideController(config, authorizer, spaceStore, repoStore, serviceAccountStore, gitrpcInterface)
apiHandler := router.ProvideAPIHandler(systemStore, authenticator, accountClient, spaceController, repoController)
gitHandler := router2.ProvideGitHandler(repoStore, authenticator)
gitHandler := router2.ProvideGitHandler(repoStore, authenticator, gitrpcInterface)
webHandler := router2.ProvideWebHandler(systemStore)
routerRouter := router2.ProvideRouter(apiHandler, gitHandler, webHandler)
serverServer := server.ProvideServer(config, routerRouter)

View File

@ -50,7 +50,7 @@ func initSystem(ctx context.Context, config *types.Config) (*system, error) {
spaceController := space.NewController(authorizer, spaceStore, repoStore, serviceAccountStore)
serviceaccountController := serviceaccount.NewController(authorizer, serviceAccountStore, spaceStore, repoStore, tokenStore)
apiHandler := router.ProvideAPIHandler(systemStore, authenticator, repoController, spaceController, serviceaccountController, controller)
gitHandler := router.ProvideGitHandler(repoStore, authenticator)
gitHandler := router.ProvideGitHandler(repoStore, authenticator, gitrpcInterface)
webHandler := router.ProvideWebHandler(systemStore)
routerRouter := router.ProvideRouter(apiHandler, gitHandler, webHandler)
serverServer := server.ProvideServer(config, routerRouter)

View File

@ -0,0 +1,151 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package repo
import (
"compress/gzip"
"context"
"fmt"
"net/http"
"strings"
"time"
"github.com/harness/gitness/internal/gitrpc"
"github.com/harness/gitness/types"
"github.com/rs/zerolog"
"github.com/rs/zerolog/hlog"
)
type CtxRepoType string
const (
CtxRepoKey CtxRepoType = "repo"
)
func GetInfoRefs(client gitrpc.Interface) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
log := hlog.FromRequest(r)
repo, ok := r.Context().Value(CtxRepoKey).(*types.Repository)
if !ok {
ctxKeyError(w, log)
return
}
// Clients MUST NOT reuse or revalidate a cached response.
// Servers MUST include sufficient Cache-Control headers to prevent caching of the response.
// https://git-scm.com/docs/http-protocol
setHeaderNoCache(w)
service := getServiceType(r)
log.Debug().Msgf("in GetInfoRefs: git service: %v", service)
w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service))
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
if err := client.GetInfoRefs(ctx, w, &gitrpc.InfoRefsParams{
RepoUID: repo.GitUID,
Service: service,
Options: nil,
GitProtocol: r.Header.Get("Git-Protocol"),
}); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
log.Err(err).Msgf("in GetInfoRefs: error occurred in service %v", service)
return
}
w.WriteHeader(http.StatusOK)
}
}
func GetUploadPack(client gitrpc.Interface) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
const service = "upload-pack"
log := hlog.FromRequest(r)
repo, ok := r.Context().Value(CtxRepoKey).(*types.Repository)
if !ok {
ctxKeyError(w, log)
return
}
if err := serviceRPC(w, r, client, repo.GitUID, service, repo.CreatedBy); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
}
func PostReceivePack(client gitrpc.Interface) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
const service = "receive-pack"
log := hlog.FromRequest(r)
repo, ok := r.Context().Value(CtxRepoKey).(*types.Repository)
if !ok {
ctxKeyError(w, log)
return
}
if err := serviceRPC(w, r, client, repo.GitUID, service, repo.CreatedBy); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
}
func serviceRPC(
w http.ResponseWriter,
r *http.Request,
client gitrpc.Interface,
repo, service string,
principalID int64,
) error {
ctx := r.Context()
log := hlog.FromRequest(r)
defer func() {
if err := r.Body.Close(); err != nil {
log.Err(err).Msgf("serviceRPC: Close: %v", err)
}
}()
w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service))
var err error
reqBody := r.Body
// Handle GZIP.
if r.Header.Get("Content-Encoding") == "gzip" {
reqBody, err = gzip.NewReader(reqBody)
if err != nil {
return err
}
}
return client.ServicePack(ctx, w, &gitrpc.ServicePackParams{
RepoUID: repo,
Service: service,
Data: reqBody,
Options: nil,
PrincipalID: principalID,
GitProtocol: r.Header.Get("Git-Protocol"),
})
}
func setHeaderNoCache(w http.ResponseWriter) {
w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")
}
func getServiceType(r *http.Request) string {
serviceType := r.FormValue("service")
if !strings.HasPrefix(serviceType, "git-") {
return ""
}
return strings.Replace(serviceType, "git-", "", 1)
}
func ctxKeyError(w http.ResponseWriter, log *zerolog.Logger) {
errMsg := "key 'repo' missing in context"
http.Error(w, errMsg, http.StatusBadRequest)
log.Error().Msg(errMsg)
}

View File

@ -122,6 +122,15 @@ func extractToken(r *http.Request) string {
if bearer == "" {
return r.FormValue("access_token")
}
// pull/push git operations will require auth using
// Basic realm
if strings.HasPrefix(bearer, "Basic") {
_, tkn, ok := r.BasicAuth()
if !ok {
return ""
}
return tkn
}
bearer = strings.TrimPrefix(bearer, "Bearer ")
bearer = strings.TrimPrefix(bearer, "IdentityService ")
return bearer

View File

@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"io"
"strconv"
"time"
"github.com/harness/gitness/internal/gitrpc/rpc"
@ -242,6 +243,7 @@ type Identity struct {
type Client struct {
conn *grpc.ClientConn
repoService rpc.RepositoryServiceClient
httpService rpc.SmartHTTPServiceClient
}
func InitClient(remoteAddr string) (*Client, error) {
@ -253,6 +255,7 @@ func InitClient(remoteAddr string) (*Client, error) {
return &Client{
conn: conn,
repoService: rpc.NewRepositoryServiceClient(conn),
httpService: rpc.NewSmartHTTPServiceClient(conn),
}, nil
}
@ -519,12 +522,6 @@ func (c *Client) ListTreeNodes(ctx context.Context, params *ListTreeNodeParams)
})
}
// TODO: is this needed?
err = stream.CloseSend()
if err != nil {
return nil, fmt.Errorf("failed to close stream")
}
return &ListTreeNodeOutput{
Nodes: nodes,
}, nil
@ -582,12 +579,6 @@ func (c *Client) ListCommits(ctx context.Context, params *ListCommitsParams) (*L
output.Commits = append(output.Commits, *commit)
}
// TODO: is this needed?
err = stream.CloseSend()
if err != nil {
return nil, fmt.Errorf("failed to close stream")
}
return output, nil
}
@ -636,12 +627,6 @@ func (c *Client) ListBranches(ctx context.Context, params *ListBranchesParams) (
output.Branches = append(output.Branches, *branch)
}
// TODO: is this needed?
err = stream.CloseSend()
if err != nil {
return nil, fmt.Errorf("failed to close stream")
}
return output, nil
}
@ -727,6 +712,122 @@ func mapToRPCListBranchesSortOption(o BranchSortOption) rpc.ListBranchesRequest_
}
}
type InfoRefsParams struct {
// RepoUID is the uid of the git repository
RepoUID string
Service string
Options []string // (key, value) pair
GitProtocol string
}
func (c *Client) GetInfoRefs(ctx context.Context, w io.Writer, params *InfoRefsParams) error {
if w == nil {
return errors.New("writer cannot be nil")
}
if params == nil {
return ErrNoParamsProvided
}
stream, err := c.httpService.InfoRefs(ctx, &rpc.InfoRefsRequest{
RepoUid: params.RepoUID,
Service: params.Service,
GitConfigOptions: params.Options,
GitProtocol: params.GitProtocol,
})
if err != nil {
return fmt.Errorf("error initializing GetInfoRefs() stream: %w", err)
}
var (
response *rpc.InfoRefsResponse
)
for {
response, err = stream.Recv()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return fmt.Errorf("GetInfoRefs() error receiving stream bytes: %w", err)
}
_, err = w.Write(response.GetData())
if err != nil {
return fmt.Errorf("GetInfoRefs() error: %w", err)
}
}
return nil
}
type ServicePackParams struct {
// RepoUID is the uid of the git repository
RepoUID string
Service string
GitProtocol string
// PrincipalID used for git hooks in receive-pack service
PrincipalID int64
Data io.ReadCloser
Options []string // (key, value) pair
}
func (c *Client) ServicePack(ctx context.Context, w io.Writer, params *ServicePackParams) error {
if w == nil {
return errors.New("writer cannot be nil")
}
if params == nil {
return ErrNoParamsProvided
}
stream, err := c.httpService.ServicePack(ctx)
if err != nil {
return err
}
// send basic information
if err = stream.Send(&rpc.ServicePackRequest{
RepoUid: params.RepoUID,
Service: params.Service,
GitConfigOptions: params.Options,
GitProtocol: params.GitProtocol,
PrincipalId: strconv.FormatInt(params.PrincipalID, 10),
}); err != nil {
return err
}
// send body as stream
stdout := NewWriter(func(p []byte) error {
return stream.Send(&rpc.ServicePackRequest{
Data: p,
})
})
_, err = io.Copy(stdout, params.Data)
if err != nil {
return fmt.Errorf("PostUploadPack() error copying reader: %w", err)
}
if err = stream.CloseSend(); err != nil {
return fmt.Errorf("PostUploadPack() error closing the stream: %w", err)
}
// when we are done with inputs then we should expect
// git data
var (
response *rpc.ServicePackResponse
)
for {
response, err = stream.Recv()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return fmt.Errorf("PostUploadPack() error receiving stream bytes: %w", err)
}
_, err = w.Write(response.GetData())
if err != nil {
return fmt.Errorf("PostUploadPack() error: %w", err)
}
}
return nil
}
func mapToRPCListCommitTagsSortOption(o TagSortOption) rpc.ListCommitTagsRequest_SortOption {
switch o {
case TagSortOptionName:

14
internal/gitrpc/env.go Normal file
View File

@ -0,0 +1,14 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package gitrpc
const (
EnvRepoUID = "GITNESS_REPO_UID"
EnvRepoName = "GITNESS_REPO_NAME"
EnvPusherName = "GITNESS_PUSHER_NAME"
EnvPusherID = "GITNESS_PUSHER_ID"
EnvAppURL = "GITNESS_ROOT_URL" // base url for Gitness server
EnvPusherEmail = "GITNESS_PUSHER_EMAIL"
)

View File

@ -219,7 +219,8 @@ func giteaParsePrettyFormatLogToList(giteaRepo *gitea.Repository, logs []byte) (
// and includes the latest commit for all nodes if requested.
// IMPORTANT: recursive and includeLatestCommit can't be used together.
// Note: ref can be Branch / Tag / CommitSHA.
//nolint:gocognit,goimports // refactor if needed
//
//nolint:gocognit // refactor if needed
func (g giteaAdapter) ListTreeNodes(ctx context.Context, repoPath string,
ref string, treePath string, recursive bool, includeLatestCommit bool) ([]treeNodeWithCommit, error) {
if recursive && includeLatestCommit {

View File

@ -0,0 +1,174 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package gitrpc
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"code.gitea.io/gitea/modules/git"
"github.com/harness/gitness/internal/gitrpc/rpc"
"github.com/rs/zerolog/log"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
const (
receivePack = "receive-pack"
)
var safeGitProtocolHeader = regexp.MustCompile(`^[0-9a-zA-Z]+=[0-9a-zA-Z]+(:[0-9a-zA-Z]+=[0-9a-zA-Z]+)*$`)
type smartHTTPService struct {
rpc.UnimplementedSmartHTTPServiceServer
adapter gitAdapter
reposRoot string
}
func newHTTPService(adapter gitAdapter, gitRoot string) (*smartHTTPService, error) {
reposRoot := filepath.Join(gitRoot, repoSubdirName)
if _, err := os.Stat(reposRoot); errors.Is(err, os.ErrNotExist) {
if err = os.MkdirAll(reposRoot, 0o700); err != nil {
return nil, err
}
}
return &smartHTTPService{
adapter: adapter,
reposRoot: reposRoot,
}, nil
}
func (s *smartHTTPService) getFullPathForRepo(uid string) string {
return filepath.Join(s.reposRoot, fmt.Sprintf("%s.%s", uid, gitRepoSuffix))
}
func (s *smartHTTPService) InfoRefs(
r *rpc.InfoRefsRequest,
stream rpc.SmartHTTPService_InfoRefsServer,
) error {
environ := make([]string, 0)
environ = append(os.Environ(), environ...)
if r.GitProtocol != "" {
environ = append(environ, "GIT_PROTOCOL="+r.GitProtocol)
}
repoPath := s.getFullPathForRepo(r.GetRepoUid())
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
w := NewWriter(func(p []byte) error {
return stream.Send(&rpc.InfoRefsResponse{Data: p})
})
cmd := &bytes.Buffer{}
if err := git.NewCommand(ctx, r.GetService(), "--stateless-rpc", "--advertise-refs", ".").
Run(&git.RunOpts{
Env: environ,
Dir: repoPath,
Stdout: cmd,
}); err != nil {
return status.Errorf(codes.Internal, "InfoRefsUploadPack: cmd: %v", err)
}
if _, err := w.Write(packetWrite("# service=git-" + r.GetService() + "\n")); err != nil {
return status.Errorf(codes.Internal, "InfoRefsUploadPack: pktLine: %v", err)
}
if _, err := w.Write([]byte("0000")); err != nil {
return status.Errorf(codes.Internal, "InfoRefsUploadPack: flush: %v", err)
}
if _, err := io.Copy(w, cmd); err != nil {
return status.Errorf(codes.Internal, "InfoRefsUploadPack: %v", err)
}
return nil
}
func (s *smartHTTPService) ServicePack(stream rpc.SmartHTTPService_ServicePackServer) error {
ctx := stream.Context()
// Get basic repo data
req, err := stream.Recv()
if err != nil {
return err
}
// if client sends data as []byte raise error, needs reader
if req.Data != nil {
return status.Errorf(codes.InvalidArgument, "PostUploadPack(): non-empty Data")
}
if req.RepoUid == "" {
return status.Errorf(codes.InvalidArgument, "PostUploadPack(): repository UID is missing")
}
repoPath := s.getFullPathForRepo(req.GetRepoUid())
stdin := NewReader(func() ([]byte, error) {
resp, streamErr := stream.Recv()
return resp.GetData(), streamErr
})
stdout := NewWriter(func(p []byte) error {
return stream.Send(&rpc.ServicePackResponse{Data: p})
})
return serviceRPC(ctx, stdin, stdout, req, repoPath)
}
func serviceRPC(ctx context.Context, stdin io.Reader, stdout io.Writer, req *rpc.ServicePackRequest, dir string) error {
protocol := req.GetGitProtocol()
service := req.GetService()
principalID := req.GetPrincipalId()
repoUID := req.GetRepoUid()
environ := make([]string, 0)
if service == receivePack && principalID != "" {
environ = []string{
EnvRepoUID + "=" + repoUID,
EnvPusherID + "=" + principalID,
}
}
// set this for allow pre-receive and post-receive execute
environ = append(environ, "SSH_ORIGINAL_COMMAND="+service)
if protocol != "" && safeGitProtocolHeader.MatchString(protocol) {
environ = append(environ, "GIT_PROTOCOL="+protocol)
}
var (
stderr bytes.Buffer
)
cmd := git.NewCommand(ctx, service, "--stateless-rpc", dir)
cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", dir))
err := cmd.Run(&git.RunOpts{
Dir: dir,
Env: append(os.Environ(), environ...),
Stdout: stdout,
Stdin: stdin,
Stderr: &stderr,
UseContextTimeout: true,
})
if err != nil && err.Error() != "signal: killed" {
log.Err(err).Msgf("Fail to serve RPC(%s) in %s: %v - %s", service, dir, err, stderr.String())
}
return err
}
func packetWrite(str string) []byte {
s := strconv.FormatInt(int64(len(str)+4), 16)
if len(s)%4 != 0 {
s = strings.Repeat("0", 4-len(s)%4) + s
}
return []byte(s + str)
}

View File

@ -4,7 +4,10 @@
package gitrpc
import "context"
import (
"context"
"io"
)
type Interface interface {
CreateRepository(ctx context.Context, params *CreateRepositoryParams) (*CreateRepositoryOutput, error)
@ -15,6 +18,12 @@ type Interface interface {
ListCommits(ctx context.Context, params *ListCommitsParams) (*ListCommitsOutput, error)
ListBranches(ctx context.Context, params *ListBranchesParams) (*ListBranchesOutput, error)
ListCommitTags(ctx context.Context, params *ListCommitTagsParams) (*ListCommitTagsOutput, error)
/*
* HTTP services
*/
GetInfoRefs(ctx context.Context, w io.Writer, params *InfoRefsParams) error
ServicePack(ctx context.Context, w io.Writer, params *ServicePackParams) error
}
// gitAdapter for accessing git commands from gitea.

View File

@ -0,0 +1,55 @@
syntax = "proto3";
package rpc;
option go_package = "github.com/harness/gitness/gitrpc/rpc";
// SmartHTTPService is a service that provides RPCs required for HTTP-based Git
// clones via the smart HTTP protocol.
service SmartHTTPService {
// The response body for GET /info/refs?service=git-upload-pack
// Will be invoked when the user executes a `git fetch`, meaning the server
// will upload the packs to that user. The user doesn't upload new objects.
rpc InfoRefs(InfoRefsRequest) returns (stream InfoRefsResponse) {}
// ServicePack is just upload-pack or receive-pack
rpc ServicePack(stream ServicePackRequest) returns (stream ServicePackResponse) {}
}
message InfoRefsRequest {
string repo_uid = 1;
// Service can be: upload-pack or receive-pack
string service = 2;
// Parameters to use with git -c (key=value pairs)
repeated string git_config_options = 3;
// Git protocol version
string git_protocol = 4;
}
message InfoRefsResponse {
bytes data = 1;
}
message ServicePackRequest {
// repository should only be present only in the first message of the stream
string repo_uid = 1;
// Service can be: upload-pack or receive-pack
string service = 2;
// Raw data to be copied to stdin of 'git upload-pack'
bytes data = 3;
// Parameters to use with git -c (key=value pairs)
repeated string git_config_options = 4;
// Git protocol version
string git_protocol = 5;
// user_id become env variable, used by the Git {pre,post}-receive
// hooks. They should only be present in the first message of the stream.
string principal_id = 6;
}
message ServicePackResponse {
// Raw data from stdout of 'git upload-pack'
bytes data = 1;
}

View File

@ -0,0 +1,437 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v3.21.7
// source: http.proto
package rpc
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type InfoRefsRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
RepoUid string `protobuf:"bytes,1,opt,name=repo_uid,json=repoUid,proto3" json:"repo_uid,omitempty"`
// Service can be: upload-pack or receive-pack
Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
// Parameters to use with git -c (key=value pairs)
GitConfigOptions []string `protobuf:"bytes,3,rep,name=git_config_options,json=gitConfigOptions,proto3" json:"git_config_options,omitempty"`
// Git protocol version
GitProtocol string `protobuf:"bytes,4,opt,name=git_protocol,json=gitProtocol,proto3" json:"git_protocol,omitempty"`
}
func (x *InfoRefsRequest) Reset() {
*x = InfoRefsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_http_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InfoRefsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InfoRefsRequest) ProtoMessage() {}
func (x *InfoRefsRequest) ProtoReflect() protoreflect.Message {
mi := &file_http_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InfoRefsRequest.ProtoReflect.Descriptor instead.
func (*InfoRefsRequest) Descriptor() ([]byte, []int) {
return file_http_proto_rawDescGZIP(), []int{0}
}
func (x *InfoRefsRequest) GetRepoUid() string {
if x != nil {
return x.RepoUid
}
return ""
}
func (x *InfoRefsRequest) GetService() string {
if x != nil {
return x.Service
}
return ""
}
func (x *InfoRefsRequest) GetGitConfigOptions() []string {
if x != nil {
return x.GitConfigOptions
}
return nil
}
func (x *InfoRefsRequest) GetGitProtocol() string {
if x != nil {
return x.GitProtocol
}
return ""
}
type InfoRefsResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *InfoRefsResponse) Reset() {
*x = InfoRefsResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_http_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *InfoRefsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*InfoRefsResponse) ProtoMessage() {}
func (x *InfoRefsResponse) ProtoReflect() protoreflect.Message {
mi := &file_http_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use InfoRefsResponse.ProtoReflect.Descriptor instead.
func (*InfoRefsResponse) Descriptor() ([]byte, []int) {
return file_http_proto_rawDescGZIP(), []int{1}
}
func (x *InfoRefsResponse) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
type ServicePackRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// repository should only be present only in the first message of the stream
RepoUid string `protobuf:"bytes,1,opt,name=repo_uid,json=repoUid,proto3" json:"repo_uid,omitempty"`
// Service can be: upload-pack or receive-pack
Service string `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
// Raw data to be copied to stdin of 'git upload-pack'
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
// Parameters to use with git -c (key=value pairs)
GitConfigOptions []string `protobuf:"bytes,4,rep,name=git_config_options,json=gitConfigOptions,proto3" json:"git_config_options,omitempty"`
// Git protocol version
GitProtocol string `protobuf:"bytes,5,opt,name=git_protocol,json=gitProtocol,proto3" json:"git_protocol,omitempty"`
// user_id become env variable, used by the Git {pre,post}-receive
// hooks. They should only be present in the first message of the stream.
PrincipalId string `protobuf:"bytes,6,opt,name=principal_id,json=principalId,proto3" json:"principal_id,omitempty"`
}
func (x *ServicePackRequest) Reset() {
*x = ServicePackRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_http_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServicePackRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServicePackRequest) ProtoMessage() {}
func (x *ServicePackRequest) ProtoReflect() protoreflect.Message {
mi := &file_http_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServicePackRequest.ProtoReflect.Descriptor instead.
func (*ServicePackRequest) Descriptor() ([]byte, []int) {
return file_http_proto_rawDescGZIP(), []int{2}
}
func (x *ServicePackRequest) GetRepoUid() string {
if x != nil {
return x.RepoUid
}
return ""
}
func (x *ServicePackRequest) GetService() string {
if x != nil {
return x.Service
}
return ""
}
func (x *ServicePackRequest) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
func (x *ServicePackRequest) GetGitConfigOptions() []string {
if x != nil {
return x.GitConfigOptions
}
return nil
}
func (x *ServicePackRequest) GetGitProtocol() string {
if x != nil {
return x.GitProtocol
}
return ""
}
func (x *ServicePackRequest) GetPrincipalId() string {
if x != nil {
return x.PrincipalId
}
return ""
}
type ServicePackResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Raw data from stdout of 'git upload-pack'
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *ServicePackResponse) Reset() {
*x = ServicePackResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_http_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ServicePackResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ServicePackResponse) ProtoMessage() {}
func (x *ServicePackResponse) ProtoReflect() protoreflect.Message {
mi := &file_http_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ServicePackResponse.ProtoReflect.Descriptor instead.
func (*ServicePackResponse) Descriptor() ([]byte, []int) {
return file_http_proto_rawDescGZIP(), []int{3}
}
func (x *ServicePackResponse) GetData() []byte {
if x != nil {
return x.Data
}
return nil
}
var File_http_proto protoreflect.FileDescriptor
var file_http_proto_rawDesc = []byte{
0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x72, 0x70,
0x63, 0x22, 0x97, 0x01, 0x0a, 0x0f, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x66, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x75, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x70, 0x6f, 0x55, 0x69, 0x64,
0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69,
0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73,
0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x67, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x67, 0x69, 0x74, 0x5f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
0x67, 0x69, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x22, 0x26, 0x0a, 0x10, 0x49,
0x6e, 0x66, 0x6f, 0x52, 0x65, 0x66, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64,
0x61, 0x74, 0x61, 0x22, 0xd1, 0x01, 0x0a, 0x12, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50,
0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x65,
0x70, 0x6f, 0x5f, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65,
0x70, 0x6f, 0x55, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12,
0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64,
0x61, 0x74, 0x61, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52,
0x10, 0x67, 0x69, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e,
0x73, 0x12, 0x21, 0x0a, 0x0c, 0x67, 0x69, 0x74, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f,
0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x67, 0x69, 0x74, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x72, 0x69, 0x6e, 0x63, 0x69, 0x70, 0x61,
0x6c, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x69, 0x6e,
0x63, 0x69, 0x70, 0x61, 0x6c, 0x49, 0x64, 0x22, 0x29, 0x0a, 0x13, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12,
0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61,
0x74, 0x61, 0x32, 0x97, 0x01, 0x0a, 0x10, 0x53, 0x6d, 0x61, 0x72, 0x74, 0x48, 0x54, 0x54, 0x50,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3b, 0x0a, 0x08, 0x49, 0x6e, 0x66, 0x6f, 0x52,
0x65, 0x66, 0x73, 0x12, 0x14, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65,
0x66, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x72, 0x70, 0x63, 0x2e,
0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x66, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x00, 0x30, 0x01, 0x12, 0x46, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50,
0x61, 0x63, 0x6b, 0x12, 0x17, 0x2e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x72,
0x70, 0x63, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x27, 0x5a, 0x25,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x72, 0x6e, 0x65,
0x73, 0x73, 0x2f, 0x67, 0x69, 0x74, 0x6e, 0x65, 0x73, 0x73, 0x2f, 0x67, 0x69, 0x74, 0x72, 0x70,
0x63, 0x2f, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_http_proto_rawDescOnce sync.Once
file_http_proto_rawDescData = file_http_proto_rawDesc
)
func file_http_proto_rawDescGZIP() []byte {
file_http_proto_rawDescOnce.Do(func() {
file_http_proto_rawDescData = protoimpl.X.CompressGZIP(file_http_proto_rawDescData)
})
return file_http_proto_rawDescData
}
var file_http_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_http_proto_goTypes = []interface{}{
(*InfoRefsRequest)(nil), // 0: rpc.InfoRefsRequest
(*InfoRefsResponse)(nil), // 1: rpc.InfoRefsResponse
(*ServicePackRequest)(nil), // 2: rpc.ServicePackRequest
(*ServicePackResponse)(nil), // 3: rpc.ServicePackResponse
}
var file_http_proto_depIdxs = []int32{
0, // 0: rpc.SmartHTTPService.InfoRefs:input_type -> rpc.InfoRefsRequest
2, // 1: rpc.SmartHTTPService.ServicePack:input_type -> rpc.ServicePackRequest
1, // 2: rpc.SmartHTTPService.InfoRefs:output_type -> rpc.InfoRefsResponse
3, // 3: rpc.SmartHTTPService.ServicePack:output_type -> rpc.ServicePackResponse
2, // [2:4] is the sub-list for method output_type
0, // [0:2] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_http_proto_init() }
func file_http_proto_init() {
if File_http_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_http_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InfoRefsRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_http_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*InfoRefsResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_http_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServicePackRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_http_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ServicePackResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_http_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_http_proto_goTypes,
DependencyIndexes: file_http_proto_depIdxs,
MessageInfos: file_http_proto_msgTypes,
}.Build()
File_http_proto = out.File
file_http_proto_rawDesc = nil
file_http_proto_goTypes = nil
file_http_proto_depIdxs = nil
}

View File

@ -0,0 +1,208 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.21.7
// source: http.proto
package rpc
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// SmartHTTPServiceClient is the client API for SmartHTTPService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SmartHTTPServiceClient interface {
// The response body for GET /info/refs?service=git-upload-pack
// Will be invoked when the user executes a `git fetch`, meaning the server
// will upload the packs to that user. The user doesn't upload new objects.
InfoRefs(ctx context.Context, in *InfoRefsRequest, opts ...grpc.CallOption) (SmartHTTPService_InfoRefsClient, error)
// ServicePack is just upload-pack or receive-pack
ServicePack(ctx context.Context, opts ...grpc.CallOption) (SmartHTTPService_ServicePackClient, error)
}
type smartHTTPServiceClient struct {
cc grpc.ClientConnInterface
}
func NewSmartHTTPServiceClient(cc grpc.ClientConnInterface) SmartHTTPServiceClient {
return &smartHTTPServiceClient{cc}
}
func (c *smartHTTPServiceClient) InfoRefs(ctx context.Context, in *InfoRefsRequest, opts ...grpc.CallOption) (SmartHTTPService_InfoRefsClient, error) {
stream, err := c.cc.NewStream(ctx, &SmartHTTPService_ServiceDesc.Streams[0], "/rpc.SmartHTTPService/InfoRefs", opts...)
if err != nil {
return nil, err
}
x := &smartHTTPServiceInfoRefsClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type SmartHTTPService_InfoRefsClient interface {
Recv() (*InfoRefsResponse, error)
grpc.ClientStream
}
type smartHTTPServiceInfoRefsClient struct {
grpc.ClientStream
}
func (x *smartHTTPServiceInfoRefsClient) Recv() (*InfoRefsResponse, error) {
m := new(InfoRefsResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *smartHTTPServiceClient) ServicePack(ctx context.Context, opts ...grpc.CallOption) (SmartHTTPService_ServicePackClient, error) {
stream, err := c.cc.NewStream(ctx, &SmartHTTPService_ServiceDesc.Streams[1], "/rpc.SmartHTTPService/ServicePack", opts...)
if err != nil {
return nil, err
}
x := &smartHTTPServiceServicePackClient{stream}
return x, nil
}
type SmartHTTPService_ServicePackClient interface {
Send(*ServicePackRequest) error
Recv() (*ServicePackResponse, error)
grpc.ClientStream
}
type smartHTTPServiceServicePackClient struct {
grpc.ClientStream
}
func (x *smartHTTPServiceServicePackClient) Send(m *ServicePackRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *smartHTTPServiceServicePackClient) Recv() (*ServicePackResponse, error) {
m := new(ServicePackResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// SmartHTTPServiceServer is the server API for SmartHTTPService service.
// All implementations must embed UnimplementedSmartHTTPServiceServer
// for forward compatibility
type SmartHTTPServiceServer interface {
// The response body for GET /info/refs?service=git-upload-pack
// Will be invoked when the user executes a `git fetch`, meaning the server
// will upload the packs to that user. The user doesn't upload new objects.
InfoRefs(*InfoRefsRequest, SmartHTTPService_InfoRefsServer) error
// ServicePack is just upload-pack or receive-pack
ServicePack(SmartHTTPService_ServicePackServer) error
mustEmbedUnimplementedSmartHTTPServiceServer()
}
// UnimplementedSmartHTTPServiceServer must be embedded to have forward compatible implementations.
type UnimplementedSmartHTTPServiceServer struct {
}
func (UnimplementedSmartHTTPServiceServer) InfoRefs(*InfoRefsRequest, SmartHTTPService_InfoRefsServer) error {
return status.Errorf(codes.Unimplemented, "method InfoRefs not implemented")
}
func (UnimplementedSmartHTTPServiceServer) ServicePack(SmartHTTPService_ServicePackServer) error {
return status.Errorf(codes.Unimplemented, "method ServicePack not implemented")
}
func (UnimplementedSmartHTTPServiceServer) mustEmbedUnimplementedSmartHTTPServiceServer() {}
// UnsafeSmartHTTPServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to SmartHTTPServiceServer will
// result in compilation errors.
type UnsafeSmartHTTPServiceServer interface {
mustEmbedUnimplementedSmartHTTPServiceServer()
}
func RegisterSmartHTTPServiceServer(s grpc.ServiceRegistrar, srv SmartHTTPServiceServer) {
s.RegisterService(&SmartHTTPService_ServiceDesc, srv)
}
func _SmartHTTPService_InfoRefs_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(InfoRefsRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(SmartHTTPServiceServer).InfoRefs(m, &smartHTTPServiceInfoRefsServer{stream})
}
type SmartHTTPService_InfoRefsServer interface {
Send(*InfoRefsResponse) error
grpc.ServerStream
}
type smartHTTPServiceInfoRefsServer struct {
grpc.ServerStream
}
func (x *smartHTTPServiceInfoRefsServer) Send(m *InfoRefsResponse) error {
return x.ServerStream.SendMsg(m)
}
func _SmartHTTPService_ServicePack_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(SmartHTTPServiceServer).ServicePack(&smartHTTPServiceServicePackServer{stream})
}
type SmartHTTPService_ServicePackServer interface {
Send(*ServicePackResponse) error
Recv() (*ServicePackRequest, error)
grpc.ServerStream
}
type smartHTTPServiceServicePackServer struct {
grpc.ServerStream
}
func (x *smartHTTPServiceServicePackServer) Send(m *ServicePackResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *smartHTTPServiceServicePackServer) Recv() (*ServicePackRequest, error) {
m := new(ServicePackRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// SmartHTTPService_ServiceDesc is the grpc.ServiceDesc for SmartHTTPService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var SmartHTTPService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "rpc.SmartHTTPService",
HandlerType: (*SmartHTTPServiceServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "InfoRefs",
Handler: _SmartHTTPService_InfoRefs_Handler,
ServerStreams: true,
},
{
StreamName: "ServicePack",
Handler: _SmartHTTPService_ServicePack_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "http.proto",
}

View File

@ -27,11 +27,19 @@ func NewServer(bind string, gitRoot string) (*Server, error) {
}
s := grpc.NewServer()
store := newLocalStore()
// initialize services
repoService, err := newRepositoryService(adapter, store, gitRoot)
if err != nil {
return nil, err
}
httpService, err := newHTTPService(adapter, gitRoot)
if err != nil {
return nil, err
}
// register services
rpc.RegisterRepositoryServiceServer(s, repoService)
rpc.RegisterSmartHTTPServiceServer(s, httpService)
return &Server{
Server: s,
Bind: bind,

83
internal/gitrpc/stream.go Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2022 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package gitrpc
import "io"
const MaxBufferSize = 128 * 1024
type writer struct {
bufferSize int
sender func([]byte) error
}
type Option func(w *writer)
func WithBufferSize(size int) Option {
return func(w *writer) {
w.bufferSize = size
}
}
func NewWriter(sender func(p []byte) error, options ...Option) io.Writer {
w := &writer{
sender: sender,
}
for _, option := range options {
option(w)
}
if w.bufferSize == 0 || w.bufferSize > MaxBufferSize {
w.bufferSize = MaxBufferSize
}
return w
}
func (w *writer) Write(p []byte) (int, error) {
var sent int
for len(p) > 0 {
chunkSize := len(p)
if chunkSize > w.bufferSize {
chunkSize = w.bufferSize
}
if err := w.sender(p[:chunkSize]); err != nil {
return sent, err
}
sent += chunkSize
p = p[chunkSize:]
}
return sent, nil
}
func NewReader(receiver func() ([]byte, error)) io.Reader {
return &reader{receiver: receiver}
}
type reader struct {
receiver func() ([]byte, error)
data []byte
err error
}
func (r *reader) Read(p []byte) (int, error) {
if len(r.data) == 0 && r.err == nil {
r.data, r.err = r.receiver()
}
n := copy(p, r.data)
r.data = r.data[n:]
if len(r.data) == 0 {
return n, r.err
}
return n, nil
}

View File

@ -5,11 +5,15 @@
package router
import (
"context"
"fmt"
"net/http"
"code.gitea.io/gitea/modules/setting"
"github.com/harness/gitness/internal/api/handler/repo"
"github.com/harness/gitness/internal/gitrpc"
"github.com/harness/gitness/internal/api/middleware/accesslog"
middleware_authn "github.com/harness/gitness/internal/api/middleware/authn"
"github.com/harness/gitness/internal/api/middleware/encode"
"github.com/harness/gitness/internal/api/request"
"github.com/harness/gitness/internal/auth/authn"
@ -28,7 +32,9 @@ type GitHandler interface {
// NewGitHandler returns a new GitHandler.
func NewGitHandler(
repoStore store.RepoStore,
authenticator authn.Authenticator) GitHandler {
authenticator authn.Authenticator,
client gitrpc.Interface,
) GitHandler {
// Use go-chi router for inner routing.
r := chi.NewRouter()
@ -43,13 +49,15 @@ func NewGitHandler(
r.Use(accesslog.HlogHandler())
// for now always attempt auth - enforced per operation.
r.Use(middleware_authn.Attempt(authenticator))
r.Use(HTTPGitEnabled)
r.Route(fmt.Sprintf("/{%s}", request.PathParamRepoRef), func(r chi.Router) {
r.Use(BasicAuth("\".\"", authenticator, repoStore))
// Write operations (need auth)
r.Group(func(r chi.Router) {
// middleware for authz?
r.Handle("/git-upload-pack", stubGitHandler(repoStore))
r.Handle("/git-upload-pack", repo.GetUploadPack(client))
})
// Read operations (only need of it not public)
@ -57,8 +65,8 @@ func NewGitHandler(
// middleware for authz?
// handlers
r.Post("/git-receive-pack", stubGitHandler(repoStore))
r.Get("/info/refs", stubGitHandler(repoStore))
r.Post("/git-receive-pack", repo.PostReceivePack(client))
r.Get("/info/refs", repo.GetInfoRefs(client))
r.Get("/HEAD", stubGitHandler(repoStore))
r.Get("/objects/info/alternates", stubGitHandler(repoStore))
r.Get("/objects/info/http-alternates", stubGitHandler(repoStore))
@ -74,8 +82,60 @@ func NewGitHandler(
return encode.GitPathBefore(r)
}
func stubGitHandler(repoStore store.RepoStore) http.HandlerFunc {
func HTTPGitEnabled(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if setting.Repository.DisableHTTPGit {
w.WriteHeader(http.StatusForbidden)
_, _ = w.Write([]byte("Interacting with repositories by HTTP protocol is not allowed"))
return
}
next.ServeHTTP(w, r)
})
}
// BasicAuth implements a simple middleware handler for adding basic http auth to a route.
func BasicAuth(realm string, auth authn.Authenticator, repoStore store.RepoStore) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log := hlog.FromRequest(r)
log.Debug().Msgf("BasicAuth middleware: validate path %v", r.URL.Path)
repoPath, err := request.GetRepoRefFromPath(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
log.Err(err).Msgf("BasicAuth middleware: bad path %v", r.URL.Path)
return
}
log.Debug().Msgf("BasicAuth middleware: find repo by path %v", r.URL.Path)
repository, err := repoStore.FindByPath(r.Context(), repoPath)
if err != nil {
http.Error(w, fmt.Sprintf("Repo '%s' not found.", repoPath), http.StatusNotFound)
log.Err(err).Msgf("BasicAuth middleware: repo not found %v", r.URL.Path)
return
}
if !repository.IsPublic {
log.Debug().Msgf("BasicAuth middleware: repo %v is private", repository.Name)
_, err = auth.Authenticate(r)
if err != nil {
basicAuthFailed(w, realm)
log.Err(err).Msgf("BasicAuth middleware: authorization failed %v", r.URL.Path)
return
}
}
log.Debug().Msgf("BasicAuth middleware: serve next with CtxKey %v", repo.CtxRepoKey)
ctx := context.WithValue(r.Context(), repo.CtxRepoKey, repository)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
func basicAuthFailed(w http.ResponseWriter, realm string) {
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
w.WriteHeader(http.StatusUnauthorized)
}
func stubGitHandler(repoStore store.RepoStore) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusTeapot)
repoPath, _ := request.GetRepoRefFromPath(r)
@ -96,5 +156,5 @@ func stubGitHandler(repoStore store.RepoStore) http.HandlerFunc {
r.URL.Path,
r.URL.RawQuery,
)))
})
}
}

View File

@ -11,6 +11,7 @@ import (
"github.com/harness/gitness/internal/api/controller/space"
"github.com/harness/gitness/internal/api/controller/user"
"github.com/harness/gitness/internal/auth/authn"
"github.com/harness/gitness/internal/gitrpc"
"github.com/harness/gitness/internal/store"
)
@ -30,8 +31,12 @@ func ProvideRouter(
return NewRouter(api, git, web)
}
func ProvideGitHandler(repoStore store.RepoStore, authenticator authn.Authenticator) GitHandler {
return NewGitHandler(repoStore, authenticator)
func ProvideGitHandler(
repoStore store.RepoStore,
authenticator authn.Authenticator,
client gitrpc.Interface,
) GitHandler {
return NewGitHandler(repoStore, authenticator, client)
}
func ProvideAPIHandler(

View File

@ -179,7 +179,7 @@ type (
// Delete deletes the token with the given id.
Delete(ctx context.Context, id int64) error
// Delete deletes all tokens for a specific principal
// DeleteForPrincipal deletes all tokens for a specific principal
DeleteForPrincipal(ctx context.Context, principalID int64) error
// List returns a list of tokens of a specific type for a specific principal.

7
scripts/wire/harness.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env sh
echo "Updating harness.wire_gen.go"
go run github.com/google/wire/cmd/wire gen -tags=harness -output_file_prefix="harness." github.com/harness/gitness/cli/server
perl -ni -e 'print unless /go:generate/' cli/server/harness.wire_gen.go
perl -i -pe's/\+build !wireinject/\+build !wireinject,harness/g' cli/server/harness.wire_gen.go
perl -i -pe's/go:build !wireinject/go:build !wireinject && harness/g' cli/server/harness.wire_gen.go

7
scripts/wire/standalone.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env sh
echo "Updating standalone.wire_gen.go"
go run github.com/google/wire/cmd/wire gen -tags= -output_file_prefix="standalone." github.com/harness/gitness/cli/server
perl -ni -e 'print unless /go:generate/' cli/server/standalone.wire_gen.go
perl -i -pe's/\+build !wireinject/\+build !wireinject,!harness/g' cli/server/standalone.wire_gen.go
perl -i -pe's/go:build !wireinject/go:build !wireinject && !harness/g' cli/server/standalone.wire_gen.go

View File

@ -4,7 +4,7 @@
package enum
// Represents the type of the JWT token.
// TokenType represents the type of the JWT token.
type TokenType string
const (