File: client.go

package info (click to toggle)
gitlab-shell 14.35.0%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 23,652 kB
  • sloc: ruby: 1,129; makefile: 583; sql: 391; sh: 384
file content (136 lines) | stat: -rw-r--r-- 4,486 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package accessverifier

import (
	"context"
	"fmt"
	"net/http"

	pb "gitlab.com/gitlab-org/gitaly/v16/proto/go/gitalypb"
	"gitlab.com/gitlab-org/gitlab-shell/v14/client"
	"gitlab.com/gitlab-org/gitlab-shell/v14/internal/command/commandargs"
	"gitlab.com/gitlab-org/gitlab-shell/v14/internal/config"
	"gitlab.com/gitlab-org/gitlab-shell/v14/internal/gitlabnet"
)

const (
	sshProtocol = "ssh"
	anyChanges  = "_any"
)

type Client struct {
	client *client.GitlabNetClient
}

type Request struct {
	Action        commandargs.CommandType `json:"action"`
	Repo          string                  `json:"project"`
	Changes       string                  `json:"changes"`
	Protocol      string                  `json:"protocol"`
	KeyId         string                  `json:"key_id,omitempty"`
	Username      string                  `json:"username,omitempty"`
	Krb5Principal string                  `json:"krb5principal,omitempty"`
	CheckIp       string                  `json:"check_ip,omitempty"`
	// NamespacePath is the full path of the namespace in which the authenticated
	// user is allowed to perform operation.
	NamespacePath string `json:"namespace_path,omitempty"`
}

type Gitaly struct {
	Repo     pb.Repository     `json:"repository"`
	Address  string            `json:"address"`
	Token    string            `json:"token"`
	Features map[string]string `json:"features"`
}

type CustomPayloadData struct {
	ApiEndpoints                            []string          `json:"api_endpoints"`
	Username                                string            `json:"gl_username"`
	PrimaryRepo                             string            `json:"primary_repo"`
	UserId                                  string            `json:"gl_id,omitempty"`
	RequestHeaders                          map[string]string `json:"request_headers"`
	GeoProxyDirectToPrimary                 bool              `json:"geo_proxy_direct_to_primary"`
	GeoProxyFetchDirectToPrimary            bool              `json:"geo_proxy_fetch_direct_to_primary"`
	GeoProxyFetchDirectToPrimaryWithOptions bool              `json:"geo_proxy_fetch_direct_to_primary_with_options"`
}

type CustomPayload struct {
	Action string            `json:"action"`
	Data   CustomPayloadData `json:"data"`
}

type Response struct {
	Success          bool          `json:"status"`
	Message          string        `json:"message"`
	Repo             string        `json:"gl_repository"`
	UserId           string        `json:"gl_id"`
	KeyType          string        `json:"gl_key_type"`
	KeyId            int           `json:"gl_key_id"`
	Username         string        `json:"gl_username"`
	GitConfigOptions []string      `json:"git_config_options"`
	Gitaly           Gitaly        `json:"gitaly"`
	GitProtocol      string        `json:"git_protocol"`
	Payload          CustomPayload `json:"payload"`
	ConsoleMessages  []string      `json:"gl_console_messages"`
	Who              string
	StatusCode       int
	// NeedAudit indicates whether git event should be audited to rails.
	NeedAudit bool `json:"need_audit"`
}

func NewClient(config *config.Config) (*Client, error) {
	client, err := gitlabnet.GetClient(config)
	if err != nil {
		return nil, fmt.Errorf("Error creating http client: %v", err)
	}

	return &Client{client: client}, nil
}

func (c *Client) Verify(ctx context.Context, args *commandargs.Shell, action commandargs.CommandType, repo string) (*Response, error) {
	request := &Request{
		Action:        action,
		Repo:          repo,
		Changes:       anyChanges,
		Protocol:      sshProtocol,
		NamespacePath: args.Env.NamespacePath,
	}

	if args.GitlabUsername != "" {
		request.Username = args.GitlabUsername
	} else if args.GitlabKrb5Principal != "" {
		request.Krb5Principal = args.GitlabKrb5Principal
	} else {
		request.KeyId = args.GitlabKeyId
	}

	request.CheckIp = gitlabnet.ParseIP(args.Env.RemoteAddr)

	response, err := c.client.Post(ctx, "/allowed", request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()

	return parse(response, args)
}

func parse(hr *http.Response, args *commandargs.Shell) (*Response, error) {
	response := &Response{}
	if err := gitlabnet.ParseJSON(hr, response); err != nil {
		return nil, err
	}

	if args.GitlabKeyId != "" {
		response.Who = "key-" + args.GitlabKeyId
	} else {
		response.Who = response.UserId
	}

	response.StatusCode = hr.StatusCode

	return response, nil
}

func (r *Response) IsCustomAction() bool {
	return r.StatusCode == http.StatusMultipleChoices
}