mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-18 16:26:38 +00:00
Compare commits
11 Commits
fix/androi
...
test/proxy
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
373f014aea | ||
|
|
2df3fb959b | ||
|
|
14b0e9462b | ||
|
|
8db71b545e | ||
|
|
7c3532d8e5 | ||
|
|
1aa1eef2c5 | ||
|
|
d9418ddc1e | ||
|
|
1b4c831976 | ||
|
|
a19611d8e0 | ||
|
|
9ab6138040 | ||
|
|
c2fec57c0f |
@@ -24,6 +24,8 @@ type AccessLogEntry struct {
|
|||||||
Reason string
|
Reason string
|
||||||
UserId string `gorm:"index"`
|
UserId string `gorm:"index"`
|
||||||
AuthMethodUsed string `gorm:"index"`
|
AuthMethodUsed string `gorm:"index"`
|
||||||
|
BytesUpload int64 `gorm:"index"`
|
||||||
|
BytesDownload int64 `gorm:"index"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromProto creates an AccessLogEntry from a proto.AccessLog
|
// FromProto creates an AccessLogEntry from a proto.AccessLog
|
||||||
@@ -39,6 +41,8 @@ func (a *AccessLogEntry) FromProto(serviceLog *proto.AccessLog) {
|
|||||||
a.UserId = serviceLog.GetUserId()
|
a.UserId = serviceLog.GetUserId()
|
||||||
a.AuthMethodUsed = serviceLog.GetAuthMechanism()
|
a.AuthMethodUsed = serviceLog.GetAuthMechanism()
|
||||||
a.AccountID = serviceLog.GetAccountId()
|
a.AccountID = serviceLog.GetAccountId()
|
||||||
|
a.BytesUpload = serviceLog.GetBytesUpload()
|
||||||
|
a.BytesDownload = serviceLog.GetBytesDownload()
|
||||||
|
|
||||||
if sourceIP := serviceLog.GetSourceIp(); sourceIP != "" {
|
if sourceIP := serviceLog.GetSourceIp(); sourceIP != "" {
|
||||||
if ip, err := netip.ParseAddr(sourceIP); err == nil {
|
if ip, err := netip.ParseAddr(sourceIP); err == nil {
|
||||||
@@ -101,5 +105,7 @@ func (a *AccessLogEntry) ToAPIResponse() *api.ProxyAccessLog {
|
|||||||
AuthMethodUsed: authMethod,
|
AuthMethodUsed: authMethod,
|
||||||
CountryCode: countryCode,
|
CountryCode: countryCode,
|
||||||
CityName: cityName,
|
CityName: cityName,
|
||||||
|
BytesUpload: a.BytesUpload,
|
||||||
|
BytesDownload: a.BytesDownload,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,3 +15,12 @@ type Domain struct {
|
|||||||
Type Type `gorm:"-"`
|
Type Type `gorm:"-"`
|
||||||
Validated bool
|
Validated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EventMeta returns activity event metadata for a domain
|
||||||
|
func (d *Domain) EventMeta() map[string]any {
|
||||||
|
return map[string]any{
|
||||||
|
"domain": d.Domain,
|
||||||
|
"target_cluster": d.TargetCluster,
|
||||||
|
"validated": d.Validated,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain"
|
"github.com/netbirdio/netbird/management/internals/modules/reverseproxy/domain"
|
||||||
|
"github.com/netbirdio/netbird/management/server/account"
|
||||||
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"github.com/netbirdio/netbird/management/server/permissions"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions/modules"
|
"github.com/netbirdio/netbird/management/server/permissions/modules"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
@@ -36,16 +38,16 @@ type Manager struct {
|
|||||||
validator domain.Validator
|
validator domain.Validator
|
||||||
proxyManager proxyManager
|
proxyManager proxyManager
|
||||||
permissionsManager permissions.Manager
|
permissionsManager permissions.Manager
|
||||||
|
accountManager account.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewManager(store store, proxyMgr proxyManager, permissionsManager permissions.Manager) Manager {
|
func NewManager(store store, proxyMgr proxyManager, permissionsManager permissions.Manager, accountManager account.Manager) Manager {
|
||||||
return Manager{
|
return Manager{
|
||||||
store: store,
|
store: store,
|
||||||
proxyManager: proxyMgr,
|
proxyManager: proxyMgr,
|
||||||
validator: domain.Validator{
|
validator: domain.Validator{Resolver: net.DefaultResolver},
|
||||||
Resolver: net.DefaultResolver,
|
|
||||||
},
|
|
||||||
permissionsManager: permissionsManager,
|
permissionsManager: permissionsManager,
|
||||||
|
accountManager: accountManager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,6 +138,9 @@ func (m Manager) CreateDomain(ctx context.Context, accountID, userID, domainName
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return d, fmt.Errorf("create domain in store: %w", err)
|
return d, fmt.Errorf("create domain in store: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.accountManager.StoreEvent(ctx, userID, d.ID, accountID, activity.DomainAdded, d.EventMeta())
|
||||||
|
|
||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,10 +153,18 @@ func (m Manager) DeleteDomain(ctx context.Context, accountID, userID, domainID s
|
|||||||
return status.NewPermissionDeniedError()
|
return status.NewPermissionDeniedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d, err := m.store.GetCustomDomain(ctx, accountID, domainID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get domain from store: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
if err := m.store.DeleteCustomDomain(ctx, accountID, domainID); err != nil {
|
if err := m.store.DeleteCustomDomain(ctx, accountID, domainID); err != nil {
|
||||||
// TODO: check for "no records" type error. Because that is a success condition.
|
// TODO: check for "no records" type error. Because that is a success condition.
|
||||||
return fmt.Errorf("delete domain from store: %w", err)
|
return fmt.Errorf("delete domain from store: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.accountManager.StoreEvent(ctx, userID, domainID, accountID, activity.DomainDeleted, d.EventMeta())
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,6 +231,8 @@ func (m Manager) ValidateDomain(ctx context.Context, accountID, userID, domainID
|
|||||||
}).WithError(err).Error("update custom domain in store")
|
}).WithError(err).Error("update custom domain in store")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.accountManager.StoreEvent(context.Background(), userID, domainID, accountID, activity.DomainValidated, d.EventMeta())
|
||||||
} else {
|
} else {
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"accountID": accountID,
|
"accountID": accountID,
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ func (s *BaseServer) ProxyManager() proxy.Manager {
|
|||||||
|
|
||||||
func (s *BaseServer) ReverseProxyDomainManager() *manager.Manager {
|
func (s *BaseServer) ReverseProxyDomainManager() *manager.Manager {
|
||||||
return Create(s, func() *manager.Manager {
|
return Create(s, func() *manager.Manager {
|
||||||
m := manager.NewManager(s.Store(), s.ProxyManager(), s.PermissionsManager())
|
m := manager.NewManager(s.Store(), s.ProxyManager(), s.PermissionsManager(), s.AccountManager())
|
||||||
return &m
|
return &m
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -220,6 +220,13 @@ const (
|
|||||||
// AccountPeerExposeDisabled indicates that a user disabled peer expose for the account
|
// AccountPeerExposeDisabled indicates that a user disabled peer expose for the account
|
||||||
AccountPeerExposeDisabled Activity = 115
|
AccountPeerExposeDisabled Activity = 115
|
||||||
|
|
||||||
|
// DomainAdded indicates that a user added a custom domain
|
||||||
|
DomainAdded Activity = 116
|
||||||
|
// DomainDeleted indicates that a user deleted a custom domain
|
||||||
|
DomainDeleted Activity = 117
|
||||||
|
// DomainValidated indicates that a custom domain was validated
|
||||||
|
DomainValidated Activity = 118
|
||||||
|
|
||||||
AccountDeleted Activity = 99999
|
AccountDeleted Activity = 99999
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -364,6 +371,10 @@ var activityMap = map[Activity]Code{
|
|||||||
|
|
||||||
AccountPeerExposeEnabled: {"Account peer expose enabled", "account.setting.peer.expose.enable"},
|
AccountPeerExposeEnabled: {"Account peer expose enabled", "account.setting.peer.expose.enable"},
|
||||||
AccountPeerExposeDisabled: {"Account peer expose disabled", "account.setting.peer.expose.disable"},
|
AccountPeerExposeDisabled: {"Account peer expose disabled", "account.setting.peer.expose.disable"},
|
||||||
|
|
||||||
|
DomainAdded: {"Domain added", "domain.add"},
|
||||||
|
DomainDeleted: {"Domain deleted", "domain.delete"},
|
||||||
|
DomainValidated: {"Domain validated", "domain.validate"},
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringCode returns a string code of the activity
|
// StringCode returns a string code of the activity
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ func BuildApiBlackBoxWithDBState(t testing_tools.TB, sqlFile string, expectedPee
|
|||||||
t.Fatalf("Failed to create proxy manager: %v", err)
|
t.Fatalf("Failed to create proxy manager: %v", err)
|
||||||
}
|
}
|
||||||
proxyServiceServer := nbgrpc.NewProxyServiceServer(accessLogsManager, proxyTokenStore, pkceverifierStore, nbgrpc.ProxyOIDCConfig{}, peersManager, userManager, proxyMgr)
|
proxyServiceServer := nbgrpc.NewProxyServiceServer(accessLogsManager, proxyTokenStore, pkceverifierStore, nbgrpc.ProxyOIDCConfig{}, peersManager, userManager, proxyMgr)
|
||||||
domainManager := manager.NewManager(store, proxyMgr, permissionsManager)
|
domainManager := manager.NewManager(store, proxyMgr, permissionsManager, am)
|
||||||
serviceProxyController, err := proxymanager.NewGRPCController(proxyServiceServer, noopMeter)
|
serviceProxyController, err := proxymanager.NewGRPCController(proxyServiceServer, noopMeter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create proxy controller: %v", err)
|
t.Fatalf("Failed to create proxy controller: %v", err)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package accesslog
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -13,6 +14,23 @@ import (
|
|||||||
"github.com/netbirdio/netbird/shared/management/proto"
|
"github.com/netbirdio/netbird/shared/management/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
requestThreshold = 10000 // Log every 10k requests
|
||||||
|
bytesThreshold = 1024 * 1024 * 1024 // Log every 1GB
|
||||||
|
usageCleanupPeriod = 1 * time.Hour // Clean up stale counters every hour
|
||||||
|
usageInactiveWindow = 24 * time.Hour // Consider domain inactive if no traffic for 24 hours
|
||||||
|
)
|
||||||
|
|
||||||
|
type domainUsage struct {
|
||||||
|
requestCount int64
|
||||||
|
requestStartTime time.Time
|
||||||
|
|
||||||
|
bytesTransferred int64
|
||||||
|
bytesStartTime time.Time
|
||||||
|
|
||||||
|
lastActivity time.Time // Track last activity for cleanup
|
||||||
|
}
|
||||||
|
|
||||||
type gRPCClient interface {
|
type gRPCClient interface {
|
||||||
SendAccessLog(ctx context.Context, in *proto.SendAccessLogRequest, opts ...grpc.CallOption) (*proto.SendAccessLogResponse, error)
|
SendAccessLog(ctx context.Context, in *proto.SendAccessLogRequest, opts ...grpc.CallOption) (*proto.SendAccessLogResponse, error)
|
||||||
}
|
}
|
||||||
@@ -22,6 +40,11 @@ type Logger struct {
|
|||||||
client gRPCClient
|
client gRPCClient
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
trustedProxies []netip.Prefix
|
trustedProxies []netip.Prefix
|
||||||
|
|
||||||
|
usageMux sync.Mutex
|
||||||
|
domainUsage map[string]*domainUsage
|
||||||
|
|
||||||
|
cleanupCancel context.CancelFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogger creates a new access log Logger. The trustedProxies parameter
|
// NewLogger creates a new access log Logger. The trustedProxies parameter
|
||||||
@@ -31,10 +54,26 @@ func NewLogger(client gRPCClient, logger *log.Logger, trustedProxies []netip.Pre
|
|||||||
if logger == nil {
|
if logger == nil {
|
||||||
logger = log.StandardLogger()
|
logger = log.StandardLogger()
|
||||||
}
|
}
|
||||||
return &Logger{
|
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
l := &Logger{
|
||||||
client: client,
|
client: client,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
trustedProxies: trustedProxies,
|
trustedProxies: trustedProxies,
|
||||||
|
domainUsage: make(map[string]*domainUsage),
|
||||||
|
cleanupCancel: cancel,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start background cleanup routine
|
||||||
|
go l.cleanupStaleUsage(ctx)
|
||||||
|
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close stops the cleanup routine. Should be called during graceful shutdown.
|
||||||
|
func (l *Logger) Close() {
|
||||||
|
if l.cleanupCancel != nil {
|
||||||
|
l.cleanupCancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,6 +90,8 @@ type logEntry struct {
|
|||||||
AuthMechanism string
|
AuthMechanism string
|
||||||
UserId string
|
UserId string
|
||||||
AuthSuccess bool
|
AuthSuccess bool
|
||||||
|
BytesUpload int64
|
||||||
|
BytesDownload int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Logger) log(ctx context.Context, entry logEntry) {
|
func (l *Logger) log(ctx context.Context, entry logEntry) {
|
||||||
@@ -84,6 +125,8 @@ func (l *Logger) log(ctx context.Context, entry logEntry) {
|
|||||||
AuthMechanism: entry.AuthMechanism,
|
AuthMechanism: entry.AuthMechanism,
|
||||||
UserId: entry.UserId,
|
UserId: entry.UserId,
|
||||||
AuthSuccess: entry.AuthSuccess,
|
AuthSuccess: entry.AuthSuccess,
|
||||||
|
BytesUpload: entry.BytesUpload,
|
||||||
|
BytesDownload: entry.BytesDownload,
|
||||||
},
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
// If it fails to send on the gRPC connection, then at least log it to the error log.
|
// If it fails to send on the gRPC connection, then at least log it to the error log.
|
||||||
@@ -103,3 +146,82 @@ func (l *Logger) log(ctx context.Context, entry logEntry) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trackUsage records request and byte counts per domain, logging when thresholds are hit.
|
||||||
|
func (l *Logger) trackUsage(domain string, bytesTransferred int64) {
|
||||||
|
if domain == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l.usageMux.Lock()
|
||||||
|
defer l.usageMux.Unlock()
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
usage, exists := l.domainUsage[domain]
|
||||||
|
if !exists {
|
||||||
|
usage = &domainUsage{
|
||||||
|
requestStartTime: now,
|
||||||
|
bytesStartTime: now,
|
||||||
|
lastActivity: now,
|
||||||
|
}
|
||||||
|
l.domainUsage[domain] = usage
|
||||||
|
}
|
||||||
|
|
||||||
|
usage.lastActivity = now
|
||||||
|
|
||||||
|
usage.requestCount++
|
||||||
|
if usage.requestCount >= requestThreshold {
|
||||||
|
elapsed := time.Since(usage.requestStartTime)
|
||||||
|
l.logger.WithFields(log.Fields{
|
||||||
|
"domain": domain,
|
||||||
|
"requests": usage.requestCount,
|
||||||
|
"duration": elapsed.String(),
|
||||||
|
}).Infof("domain %s had %d requests over %s", domain, usage.requestCount, elapsed)
|
||||||
|
|
||||||
|
usage.requestCount = 0
|
||||||
|
usage.requestStartTime = now
|
||||||
|
}
|
||||||
|
|
||||||
|
usage.bytesTransferred += bytesTransferred
|
||||||
|
if usage.bytesTransferred >= bytesThreshold {
|
||||||
|
elapsed := time.Since(usage.bytesStartTime)
|
||||||
|
bytesInGB := float64(usage.bytesTransferred) / (1024 * 1024 * 1024)
|
||||||
|
l.logger.WithFields(log.Fields{
|
||||||
|
"domain": domain,
|
||||||
|
"bytes": usage.bytesTransferred,
|
||||||
|
"bytes_gb": bytesInGB,
|
||||||
|
"duration": elapsed.String(),
|
||||||
|
}).Infof("domain %s transferred %.2f GB over %s", domain, bytesInGB, elapsed)
|
||||||
|
|
||||||
|
usage.bytesTransferred = 0
|
||||||
|
usage.bytesStartTime = now
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanupStaleUsage removes usage entries for domains that have been inactive.
|
||||||
|
func (l *Logger) cleanupStaleUsage(ctx context.Context) {
|
||||||
|
ticker := time.NewTicker(usageCleanupPeriod)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
l.usageMux.Lock()
|
||||||
|
now := time.Now()
|
||||||
|
removed := 0
|
||||||
|
for domain, usage := range l.domainUsage {
|
||||||
|
if now.Sub(usage.lastActivity) > usageInactiveWindow {
|
||||||
|
delete(l.domainUsage, domain)
|
||||||
|
removed++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.usageMux.Unlock()
|
||||||
|
|
||||||
|
if removed > 0 {
|
||||||
|
l.logger.Debugf("cleaned up %d stale domain usage entries", removed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,6 +32,14 @@ func (l *Logger) Middleware(next http.Handler) http.Handler {
|
|||||||
status: http.StatusOK,
|
status: http.StatusOK,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bytesRead int64
|
||||||
|
if r.Body != nil {
|
||||||
|
r.Body = &bodyCounter{
|
||||||
|
ReadCloser: r.Body,
|
||||||
|
bytesRead: &bytesRead,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Resolve the source IP using trusted proxy configuration before passing
|
// Resolve the source IP using trusted proxy configuration before passing
|
||||||
// the request on, as the proxy will modify forwarding headers.
|
// the request on, as the proxy will modify forwarding headers.
|
||||||
sourceIp := extractSourceIP(r, l.trustedProxies)
|
sourceIp := extractSourceIP(r, l.trustedProxies)
|
||||||
@@ -53,6 +61,9 @@ func (l *Logger) Middleware(next http.Handler) http.Handler {
|
|||||||
host = r.Host
|
host = r.Host
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bytesUpload := bytesRead
|
||||||
|
bytesDownload := sw.bytesWritten
|
||||||
|
|
||||||
entry := logEntry{
|
entry := logEntry{
|
||||||
ID: requestID,
|
ID: requestID,
|
||||||
ServiceId: capturedData.GetServiceId(),
|
ServiceId: capturedData.GetServiceId(),
|
||||||
@@ -66,10 +77,15 @@ func (l *Logger) Middleware(next http.Handler) http.Handler {
|
|||||||
AuthMechanism: capturedData.GetAuthMethod(),
|
AuthMechanism: capturedData.GetAuthMethod(),
|
||||||
UserId: capturedData.GetUserID(),
|
UserId: capturedData.GetUserID(),
|
||||||
AuthSuccess: sw.status != http.StatusUnauthorized && sw.status != http.StatusForbidden,
|
AuthSuccess: sw.status != http.StatusUnauthorized && sw.status != http.StatusForbidden,
|
||||||
|
BytesUpload: bytesUpload,
|
||||||
|
BytesDownload: bytesDownload,
|
||||||
}
|
}
|
||||||
l.logger.Debugf("response: request_id=%s method=%s host=%s path=%s status=%d duration=%dms source=%s origin=%s service=%s account=%s",
|
l.logger.Debugf("response: request_id=%s method=%s host=%s path=%s status=%d duration=%dms source=%s origin=%s service=%s account=%s",
|
||||||
requestID, r.Method, host, r.URL.Path, sw.status, duration.Milliseconds(), sourceIp, capturedData.GetOrigin(), capturedData.GetServiceId(), capturedData.GetAccountId())
|
requestID, r.Method, host, r.URL.Path, sw.status, duration.Milliseconds(), sourceIp, capturedData.GetOrigin(), capturedData.GetServiceId(), capturedData.GetAccountId())
|
||||||
|
|
||||||
l.log(r.Context(), entry)
|
l.log(r.Context(), entry)
|
||||||
|
|
||||||
|
// Track usage for cost monitoring (upload + download) by domain
|
||||||
|
l.trackUsage(host, bytesUpload+bytesDownload)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,39 @@
|
|||||||
package accesslog
|
package accesslog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/proxy/internal/responsewriter"
|
"github.com/netbirdio/netbird/proxy/internal/responsewriter"
|
||||||
)
|
)
|
||||||
|
|
||||||
// statusWriter captures the HTTP status code from WriteHeader calls.
|
// statusWriter captures the HTTP status code and bytes written from responses.
|
||||||
// It embeds responsewriter.PassthroughWriter which handles all the optional
|
// It embeds responsewriter.PassthroughWriter which handles all the optional
|
||||||
// interfaces (Hijacker, Flusher, Pusher) automatically.
|
// interfaces (Hijacker, Flusher, Pusher) automatically.
|
||||||
type statusWriter struct {
|
type statusWriter struct {
|
||||||
*responsewriter.PassthroughWriter
|
*responsewriter.PassthroughWriter
|
||||||
status int
|
status int
|
||||||
|
bytesWritten int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *statusWriter) WriteHeader(status int) {
|
func (w *statusWriter) WriteHeader(status int) {
|
||||||
w.status = status
|
w.status = status
|
||||||
w.PassthroughWriter.WriteHeader(status)
|
w.PassthroughWriter.WriteHeader(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *statusWriter) Write(b []byte) (int, error) {
|
||||||
|
n, err := w.PassthroughWriter.Write(b)
|
||||||
|
w.bytesWritten += int64(n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// bodyCounter wraps an io.ReadCloser and counts bytes read from the request body.
|
||||||
|
type bodyCounter struct {
|
||||||
|
io.ReadCloser
|
||||||
|
bytesRead *int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *bodyCounter) Read(p []byte) (int, error) {
|
||||||
|
n, err := bc.ReadCloser.Read(p)
|
||||||
|
*bc.bytesRead += int64(n)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ type domainInfo struct {
|
|||||||
err string
|
err string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type metricsRecorder interface {
|
||||||
|
RecordCertificateIssuance(duration time.Duration)
|
||||||
|
}
|
||||||
|
|
||||||
// Manager wraps autocert.Manager with domain tracking and cross-replica
|
// Manager wraps autocert.Manager with domain tracking and cross-replica
|
||||||
// coordination via a pluggable locking strategy. The locker prevents
|
// coordination via a pluggable locking strategy. The locker prevents
|
||||||
// duplicate ACME requests when multiple replicas share a certificate cache.
|
// duplicate ACME requests when multiple replicas share a certificate cache.
|
||||||
@@ -55,6 +59,7 @@ type Manager struct {
|
|||||||
|
|
||||||
certNotifier certificateNotifier
|
certNotifier certificateNotifier
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
|
metrics metricsRecorder
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager creates a new ACME certificate manager. The certDir is used
|
// NewManager creates a new ACME certificate manager. The certDir is used
|
||||||
@@ -63,7 +68,7 @@ type Manager struct {
|
|||||||
// eabKID and eabHMACKey are optional External Account Binding credentials
|
// eabKID and eabHMACKey are optional External Account Binding credentials
|
||||||
// required for some CAs like ZeroSSL. The eabHMACKey should be the base64
|
// required for some CAs like ZeroSSL. The eabHMACKey should be the base64
|
||||||
// URL-encoded string provided by the CA.
|
// URL-encoded string provided by the CA.
|
||||||
func NewManager(certDir, acmeURL, eabKID, eabHMACKey string, notifier certificateNotifier, logger *log.Logger, lockMethod CertLockMethod) *Manager {
|
func NewManager(certDir, acmeURL, eabKID, eabHMACKey string, notifier certificateNotifier, logger *log.Logger, lockMethod CertLockMethod, metrics metricsRecorder) *Manager {
|
||||||
if logger == nil {
|
if logger == nil {
|
||||||
logger = log.StandardLogger()
|
logger = log.StandardLogger()
|
||||||
}
|
}
|
||||||
@@ -73,6 +78,7 @@ func NewManager(certDir, acmeURL, eabKID, eabHMACKey string, notifier certificat
|
|||||||
domains: make(map[domain.Domain]*domainInfo),
|
domains: make(map[domain.Domain]*domainInfo),
|
||||||
certNotifier: notifier,
|
certNotifier: notifier,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
|
metrics: metrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
var eab *acme.ExternalAccountBinding
|
var eab *acme.ExternalAccountBinding
|
||||||
@@ -129,24 +135,45 @@ func (mgr *Manager) AddDomain(d domain.Domain, accountID, serviceID string) {
|
|||||||
|
|
||||||
// prefetchCertificate proactively triggers certificate generation for a domain.
|
// prefetchCertificate proactively triggers certificate generation for a domain.
|
||||||
// It acquires a distributed lock to prevent multiple replicas from issuing
|
// It acquires a distributed lock to prevent multiple replicas from issuing
|
||||||
// duplicate ACME requests. The second replica will block until the first
|
// duplicate ACME requests. If the certificate appears in the cache while waiting
|
||||||
// finishes, then find the certificate in the cache.
|
// for the lock, it cancels the wait and uses the cached certificate.
|
||||||
func (mgr *Manager) prefetchCertificate(d domain.Domain) {
|
func (mgr *Manager) prefetchCertificate(d domain.Domain) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
name := d.PunycodeString()
|
name := d.PunycodeString()
|
||||||
|
|
||||||
|
if mgr.certExistsInCache(ctx, name) {
|
||||||
|
mgr.logger.Infof("certificate for domain %q already exists in cache before lock attempt", name)
|
||||||
|
mgr.loadAndFinalizeCachedCert(ctx, d, name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go mgr.pollCacheAndCancel(ctx, name, cancel)
|
||||||
|
|
||||||
|
// Acquire lock
|
||||||
mgr.logger.Infof("acquiring cert lock for domain %q", name)
|
mgr.logger.Infof("acquiring cert lock for domain %q", name)
|
||||||
lockStart := time.Now()
|
lockStart := time.Now()
|
||||||
unlock, err := mgr.locker.Lock(ctx, name)
|
unlock, err := mgr.locker.Lock(ctx, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mgr.logger.Warnf("acquire cert lock for domain %q, proceeding without lock: %v", name, err)
|
if mgr.certExistsInCache(context.Background(), name) {
|
||||||
|
mgr.logger.Infof("certificate for domain %q appeared in cache while waiting for lock", name)
|
||||||
|
mgr.loadAndFinalizeCachedCert(context.Background(), d, name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mgr.logger.Warnf("acquire cert lock for domain %q: %v", name, err)
|
||||||
|
// Continue without lock
|
||||||
} else {
|
} else {
|
||||||
mgr.logger.Infof("acquired cert lock for domain %q in %s", name, time.Since(lockStart))
|
mgr.logger.Infof("acquired cert lock for domain %q in %s", name, time.Since(lockStart))
|
||||||
defer unlock()
|
defer unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mgr.certExistsInCache(ctx, name) {
|
||||||
|
mgr.logger.Infof("certificate for domain %q already exists in cache after lock acquisition, skipping ACME request", name)
|
||||||
|
mgr.loadAndFinalizeCachedCert(ctx, d, name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
hello := &tls.ClientHelloInfo{
|
hello := &tls.ClientHelloInfo{
|
||||||
ServerName: name,
|
ServerName: name,
|
||||||
Conn: &dummyConn{ctx: ctx},
|
Conn: &dummyConn{ctx: ctx},
|
||||||
@@ -161,6 +188,10 @@ func (mgr *Manager) prefetchCertificate(d domain.Domain) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if mgr.metrics != nil {
|
||||||
|
mgr.metrics.RecordCertificateIssuance(elapsed)
|
||||||
|
}
|
||||||
|
|
||||||
mgr.setDomainState(d, domainReady, "")
|
mgr.setDomainState(d, domainReady, "")
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
@@ -199,6 +230,78 @@ func (mgr *Manager) setDomainState(d domain.Domain, state domainState, errMsg st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// certExistsInCache checks if a certificate exists on the shared disk for the given domain.
|
||||||
|
func (mgr *Manager) certExistsInCache(ctx context.Context, domain string) bool {
|
||||||
|
if mgr.Cache == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
_, err := mgr.Cache.Get(ctx, domain)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pollCacheAndCancel periodically checks if a certificate appears in the cache.
|
||||||
|
// If found, it cancels the context to abort the lock wait.
|
||||||
|
func (mgr *Manager) pollCacheAndCancel(ctx context.Context, domain string, cancel context.CancelFunc) {
|
||||||
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-ticker.C:
|
||||||
|
if mgr.certExistsInCache(context.Background(), domain) {
|
||||||
|
mgr.logger.Debugf("cert detected in cache for domain %q, cancelling lock wait", domain)
|
||||||
|
cancel()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadAndFinalizeCachedCert loads a certificate from cache and updates domain state.
|
||||||
|
func (mgr *Manager) loadAndFinalizeCachedCert(ctx context.Context, d domain.Domain, name string) {
|
||||||
|
hello := &tls.ClientHelloInfo{
|
||||||
|
ServerName: name,
|
||||||
|
Conn: &dummyConn{ctx: ctx},
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := mgr.GetCertificate(hello)
|
||||||
|
if err != nil {
|
||||||
|
mgr.logger.Warnf("load cached certificate for domain %q: %v", name, err)
|
||||||
|
mgr.setDomainState(d, domainFailed, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr.setDomainState(d, domainReady, "")
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
if cert != nil && cert.Leaf != nil {
|
||||||
|
leaf := cert.Leaf
|
||||||
|
mgr.logger.Infof("loaded cached certificate for domain %q: serial=%s SANs=%v notBefore=%s, notAfter=%s, now=%s",
|
||||||
|
name,
|
||||||
|
leaf.SerialNumber.Text(16),
|
||||||
|
leaf.DNSNames,
|
||||||
|
leaf.NotBefore.UTC().Format(time.RFC3339),
|
||||||
|
leaf.NotAfter.UTC().Format(time.RFC3339),
|
||||||
|
now.UTC().Format(time.RFC3339),
|
||||||
|
)
|
||||||
|
mgr.logCertificateDetails(name, leaf, now)
|
||||||
|
} else {
|
||||||
|
mgr.logger.Infof("loaded cached certificate for domain %q", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr.mu.RLock()
|
||||||
|
info := mgr.domains[d]
|
||||||
|
mgr.mu.RUnlock()
|
||||||
|
|
||||||
|
if info != nil && mgr.certNotifier != nil {
|
||||||
|
if err := mgr.certNotifier.NotifyCertificateIssued(ctx, info.accountID, info.serviceID, name); err != nil {
|
||||||
|
mgr.logger.Warnf("notify certificate ready for domain %q: %v", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// logCertificateDetails logs certificate validity and SCT timestamps.
|
// logCertificateDetails logs certificate validity and SCT timestamps.
|
||||||
func (mgr *Manager) logCertificateDetails(domain string, cert *x509.Certificate, now time.Time) {
|
func (mgr *Manager) logCertificateDetails(domain string, cert *x509.Certificate, now time.Time) {
|
||||||
if cert.NotBefore.After(now) {
|
if cert.NotBefore.After(now) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestHostPolicy(t *testing.T) {
|
func TestHostPolicy(t *testing.T) {
|
||||||
mgr := NewManager(t.TempDir(), "https://acme.example.com/directory", "", "", nil, nil, "")
|
mgr := NewManager(t.TempDir(), "https://acme.example.com/directory", "", "", nil, nil, "", nil)
|
||||||
mgr.AddDomain("example.com", "acc1", "rp1")
|
mgr.AddDomain("example.com", "acc1", "rp1")
|
||||||
|
|
||||||
// Wait for the background prefetch goroutine to finish so the temp dir
|
// Wait for the background prefetch goroutine to finish so the temp dir
|
||||||
@@ -70,7 +70,7 @@ func TestHostPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDomainStates(t *testing.T) {
|
func TestDomainStates(t *testing.T) {
|
||||||
mgr := NewManager(t.TempDir(), "https://acme.example.com/directory", "", "", nil, nil, "")
|
mgr := NewManager(t.TempDir(), "https://acme.example.com/directory", "", "", nil, nil, "", nil)
|
||||||
|
|
||||||
assert.Equal(t, 0, mgr.PendingCerts(), "initially zero")
|
assert.Equal(t, 0, mgr.PendingCerts(), "initially zero")
|
||||||
assert.Equal(t, 0, mgr.TotalDomains(), "initially zero domains")
|
assert.Equal(t, 0, mgr.TotalDomains(), "initially zero domains")
|
||||||
|
|||||||
@@ -1,64 +1,106 @@
|
|||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"go.opentelemetry.io/otel/metric"
|
||||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/proxy/internal/proxy"
|
"github.com/netbirdio/netbird/proxy/internal/proxy"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/responsewriter"
|
"github.com/netbirdio/netbird/proxy/internal/responsewriter"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
requestsTotal prometheus.Counter
|
ctx context.Context
|
||||||
activeRequests prometheus.Gauge
|
requestsTotal metric.Int64Counter
|
||||||
configuredDomains prometheus.Gauge
|
activeRequests metric.Int64UpDownCounter
|
||||||
pathsPerDomain *prometheus.GaugeVec
|
configuredDomains metric.Int64UpDownCounter
|
||||||
requestDuration *prometheus.HistogramVec
|
totalPaths metric.Int64UpDownCounter
|
||||||
backendDuration *prometheus.HistogramVec
|
requestDuration metric.Int64Histogram
|
||||||
|
backendDuration metric.Int64Histogram
|
||||||
|
certificateIssueDuration metric.Int64Histogram
|
||||||
|
|
||||||
|
mappingsMux sync.Mutex
|
||||||
|
mappingPaths map[string]int
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(reg prometheus.Registerer) *Metrics {
|
func New(ctx context.Context, meter metric.Meter) (*Metrics, error) {
|
||||||
promFactory := promauto.With(reg)
|
requestsTotal, err := meter.Int64Counter(
|
||||||
return &Metrics{
|
"proxy.http.request.counter",
|
||||||
requestsTotal: promFactory.NewCounter(prometheus.CounterOpts{
|
metric.WithUnit("1"),
|
||||||
Name: "netbird_proxy_requests_total",
|
metric.WithDescription("Total number of requests made to the netbird proxy"),
|
||||||
Help: "Total number of requests made to the netbird proxy",
|
)
|
||||||
}),
|
if err != nil {
|
||||||
activeRequests: promFactory.NewGauge(prometheus.GaugeOpts{
|
return nil, err
|
||||||
Name: "netbird_proxy_active_requests_count",
|
|
||||||
Help: "Current in-flight requests handled by the netbird proxy",
|
|
||||||
}),
|
|
||||||
configuredDomains: promFactory.NewGauge(prometheus.GaugeOpts{
|
|
||||||
Name: "netbird_proxy_domains_count",
|
|
||||||
Help: "Current number of domains configured on the netbird proxy",
|
|
||||||
}),
|
|
||||||
pathsPerDomain: promFactory.NewGaugeVec(
|
|
||||||
prometheus.GaugeOpts{
|
|
||||||
Name: "netbird_proxy_paths_count",
|
|
||||||
Help: "Current number of paths configured on the netbird proxy labelled by domain",
|
|
||||||
},
|
|
||||||
[]string{"domain"},
|
|
||||||
),
|
|
||||||
requestDuration: promFactory.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "netbird_proxy_request_duration_seconds",
|
|
||||||
Help: "Duration of requests made to the netbird proxy",
|
|
||||||
Buckets: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10},
|
|
||||||
},
|
|
||||||
[]string{"status", "size", "method", "host", "path"},
|
|
||||||
),
|
|
||||||
backendDuration: promFactory.NewHistogramVec(prometheus.HistogramOpts{
|
|
||||||
Name: "netbird_proxy_backend_duration_seconds",
|
|
||||||
Help: "Duration of peer round trip time from the netbird proxy",
|
|
||||||
Buckets: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10},
|
|
||||||
},
|
|
||||||
[]string{"status", "size", "method", "host", "path"},
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activeRequests, err := meter.Int64UpDownCounter(
|
||||||
|
"proxy.http.active_requests",
|
||||||
|
metric.WithUnit("1"),
|
||||||
|
metric.WithDescription("Current in-flight requests handled by the netbird proxy"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
configuredDomains, err := meter.Int64UpDownCounter(
|
||||||
|
"proxy.domains.count",
|
||||||
|
metric.WithUnit("1"),
|
||||||
|
metric.WithDescription("Current number of domains configured on the netbird proxy"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
totalPaths, err := meter.Int64UpDownCounter(
|
||||||
|
"proxy.paths.count",
|
||||||
|
metric.WithUnit("1"),
|
||||||
|
metric.WithDescription("Total number of paths configured on the netbird proxy"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
requestDuration, err := meter.Int64Histogram(
|
||||||
|
"proxy.http.request.duration.ms",
|
||||||
|
metric.WithUnit("milliseconds"),
|
||||||
|
metric.WithDescription("Duration of requests made to the netbird proxy"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
backendDuration, err := meter.Int64Histogram(
|
||||||
|
"proxy.backend.duration.ms",
|
||||||
|
metric.WithUnit("milliseconds"),
|
||||||
|
metric.WithDescription("Duration of peer round trip time from the netbird proxy"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
certificateIssueDuration, err := meter.Int64Histogram(
|
||||||
|
"proxy.certificate.issue.duration.ms",
|
||||||
|
metric.WithUnit("milliseconds"),
|
||||||
|
metric.WithDescription("Duration of ACME certificate issuance"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Metrics{
|
||||||
|
ctx: ctx,
|
||||||
|
requestsTotal: requestsTotal,
|
||||||
|
activeRequests: activeRequests,
|
||||||
|
configuredDomains: configuredDomains,
|
||||||
|
totalPaths: totalPaths,
|
||||||
|
requestDuration: requestDuration,
|
||||||
|
backendDuration: backendDuration,
|
||||||
|
certificateIssueDuration: certificateIssueDuration,
|
||||||
|
mappingPaths: make(map[string]int),
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type responseInterceptor struct {
|
type responseInterceptor struct {
|
||||||
@@ -80,23 +122,19 @@ func (w *responseInterceptor) Write(b []byte) (int, error) {
|
|||||||
|
|
||||||
func (m *Metrics) Middleware(next http.Handler) http.Handler {
|
func (m *Metrics) Middleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
m.requestsTotal.Inc()
|
m.requestsTotal.Add(m.ctx, 1)
|
||||||
m.activeRequests.Inc()
|
m.activeRequests.Add(m.ctx, 1)
|
||||||
|
|
||||||
interceptor := &responseInterceptor{PassthroughWriter: responsewriter.New(w)}
|
interceptor := &responseInterceptor{PassthroughWriter: responsewriter.New(w)}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
next.ServeHTTP(interceptor, r)
|
defer func() {
|
||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
|
m.activeRequests.Add(m.ctx, -1)
|
||||||
|
m.requestDuration.Record(m.ctx, duration.Milliseconds())
|
||||||
|
}()
|
||||||
|
|
||||||
m.activeRequests.Desc()
|
next.ServeHTTP(interceptor, r)
|
||||||
m.requestDuration.With(prometheus.Labels{
|
|
||||||
"status": strconv.Itoa(interceptor.status),
|
|
||||||
"size": strconv.Itoa(interceptor.size),
|
|
||||||
"method": r.Method,
|
|
||||||
"host": r.Host,
|
|
||||||
"path": r.URL.Path,
|
|
||||||
}).Observe(duration.Seconds())
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,44 +146,52 @@ func (f roundTripperFunc) RoundTrip(r *http.Request) (*http.Response, error) {
|
|||||||
|
|
||||||
func (m *Metrics) RoundTripper(next http.RoundTripper) http.RoundTripper {
|
func (m *Metrics) RoundTripper(next http.RoundTripper) http.RoundTripper {
|
||||||
return roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
return roundTripperFunc(func(req *http.Request) (*http.Response, error) {
|
||||||
labels := prometheus.Labels{
|
|
||||||
"method": req.Method,
|
|
||||||
"host": req.Host,
|
|
||||||
// Fill potentially empty labels with default values to avoid cardinality issues.
|
|
||||||
"path": "/",
|
|
||||||
"status": "0",
|
|
||||||
"size": "0",
|
|
||||||
}
|
|
||||||
if req.URL != nil {
|
|
||||||
labels["path"] = req.URL.Path
|
|
||||||
}
|
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
res, err := next.RoundTrip(req)
|
res, err := next.RoundTrip(req)
|
||||||
duration := time.Since(start)
|
duration := time.Since(start)
|
||||||
|
|
||||||
// Not all labels will be available if there was an error.
|
m.backendDuration.Record(m.ctx, duration.Milliseconds())
|
||||||
if res != nil {
|
|
||||||
labels["status"] = strconv.Itoa(res.StatusCode)
|
|
||||||
labels["size"] = strconv.Itoa(int(res.ContentLength))
|
|
||||||
}
|
|
||||||
|
|
||||||
m.backendDuration.With(labels).Observe(duration.Seconds())
|
|
||||||
|
|
||||||
return res, err
|
return res, err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Metrics) AddMapping(mapping proxy.Mapping) {
|
func (m *Metrics) AddMapping(mapping proxy.Mapping) {
|
||||||
m.configuredDomains.Inc()
|
m.mappingsMux.Lock()
|
||||||
m.pathsPerDomain.With(prometheus.Labels{
|
defer m.mappingsMux.Unlock()
|
||||||
"domain": mapping.Host,
|
|
||||||
}).Set(float64(len(mapping.Paths)))
|
newPathCount := len(mapping.Paths)
|
||||||
|
oldPathCount, exists := m.mappingPaths[mapping.Host]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
m.configuredDomains.Add(m.ctx, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pathDelta := newPathCount - oldPathCount
|
||||||
|
if pathDelta != 0 {
|
||||||
|
m.totalPaths.Add(m.ctx, int64(pathDelta))
|
||||||
|
}
|
||||||
|
|
||||||
|
m.mappingPaths[mapping.Host] = newPathCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Metrics) RemoveMapping(mapping proxy.Mapping) {
|
func (m *Metrics) RemoveMapping(mapping proxy.Mapping) {
|
||||||
m.configuredDomains.Dec()
|
m.mappingsMux.Lock()
|
||||||
m.pathsPerDomain.With(prometheus.Labels{
|
defer m.mappingsMux.Unlock()
|
||||||
"domain": mapping.Host,
|
|
||||||
}).Set(0)
|
oldPathCount, exists := m.mappingPaths[mapping.Host]
|
||||||
|
if !exists {
|
||||||
|
// Nothing to remove
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.configuredDomains.Add(m.ctx, -1)
|
||||||
|
m.totalPaths.Add(m.ctx, -int64(oldPathCount))
|
||||||
|
|
||||||
|
delete(m.mappingPaths, mapping.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RecordCertificateIssuance records the duration of a certificate issuance.
|
||||||
|
func (m *Metrics) RecordCertificateIssuance(duration time.Duration) {
|
||||||
|
m.certificateIssueDuration.Record(m.ctx, duration.Milliseconds())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
package metrics_test
|
package metrics_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
"go.opentelemetry.io/otel/exporters/prometheus"
|
||||||
|
"go.opentelemetry.io/otel/sdk/metric"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/proxy/internal/metrics"
|
"github.com/netbirdio/netbird/proxy/internal/metrics"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type testRoundTripper struct {
|
type testRoundTripper struct {
|
||||||
@@ -47,7 +51,19 @@ func TestMetrics_RoundTripper(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
m := metrics.New(prometheus.NewRegistry())
|
exporter, err := prometheus.New()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("create prometheus exporter: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := metric.NewMeterProvider(metric.WithReader(exporter))
|
||||||
|
pkg := reflect.TypeOf(metrics.Metrics{}).PkgPath()
|
||||||
|
meter := provider.Meter(pkg)
|
||||||
|
|
||||||
|
m, err := metrics.New(context.Background(), meter)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("create metrics: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
|
|||||||
@@ -19,14 +19,17 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cenkalti/backoff/v4"
|
"github.com/cenkalti/backoff/v4"
|
||||||
"github.com/pires/go-proxyproto"
|
"github.com/pires/go-proxyproto"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
prometheus2 "github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
"go.opentelemetry.io/otel/exporters/prometheus"
|
||||||
|
"go.opentelemetry.io/otel/sdk/metric"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
@@ -42,7 +45,7 @@ import (
|
|||||||
proxygrpc "github.com/netbirdio/netbird/proxy/internal/grpc"
|
proxygrpc "github.com/netbirdio/netbird/proxy/internal/grpc"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/health"
|
"github.com/netbirdio/netbird/proxy/internal/health"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/k8s"
|
"github.com/netbirdio/netbird/proxy/internal/k8s"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/metrics"
|
proxymetrics "github.com/netbirdio/netbird/proxy/internal/metrics"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/proxy"
|
"github.com/netbirdio/netbird/proxy/internal/proxy"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/roundtrip"
|
"github.com/netbirdio/netbird/proxy/internal/roundtrip"
|
||||||
"github.com/netbirdio/netbird/proxy/internal/types"
|
"github.com/netbirdio/netbird/proxy/internal/types"
|
||||||
@@ -63,7 +66,7 @@ type Server struct {
|
|||||||
debug *http.Server
|
debug *http.Server
|
||||||
healthServer *health.Server
|
healthServer *health.Server
|
||||||
healthChecker *health.Checker
|
healthChecker *health.Checker
|
||||||
meter *metrics.Metrics
|
meter *proxymetrics.Metrics
|
||||||
|
|
||||||
// hijackTracker tracks hijacked connections (e.g. WebSocket upgrades)
|
// hijackTracker tracks hijacked connections (e.g. WebSocket upgrades)
|
||||||
// so they can be closed during graceful shutdown, since http.Server.Shutdown
|
// so they can be closed during graceful shutdown, since http.Server.Shutdown
|
||||||
@@ -152,8 +155,19 @@ func (s *Server) NotifyCertificateIssued(ctx context.Context, accountID, service
|
|||||||
func (s *Server) ListenAndServe(ctx context.Context, addr string) (err error) {
|
func (s *Server) ListenAndServe(ctx context.Context, addr string) (err error) {
|
||||||
s.initDefaults()
|
s.initDefaults()
|
||||||
|
|
||||||
reg := prometheus.NewRegistry()
|
exporter, err := prometheus.New()
|
||||||
s.meter = metrics.New(reg)
|
if err != nil {
|
||||||
|
return fmt.Errorf("create prometheus exporter: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
provider := metric.NewMeterProvider(metric.WithReader(exporter))
|
||||||
|
pkg := reflect.TypeOf(Server{}).PkgPath()
|
||||||
|
meter := provider.Meter(pkg)
|
||||||
|
|
||||||
|
s.meter, err = proxymetrics.New(ctx, meter)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("create metrics: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
mgmtConn, err := s.dialManagement()
|
mgmtConn, err := s.dialManagement()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -193,7 +207,7 @@ func (s *Server) ListenAndServe(ctx context.Context, addr string) (err error) {
|
|||||||
|
|
||||||
s.startDebugEndpoint()
|
s.startDebugEndpoint()
|
||||||
|
|
||||||
if err := s.startHealthServer(reg); err != nil {
|
if err := s.startHealthServer(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,12 +298,12 @@ func (s *Server) startDebugEndpoint() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// startHealthServer launches the health probe and metrics server.
|
// startHealthServer launches the health probe and metrics server.
|
||||||
func (s *Server) startHealthServer(reg *prometheus.Registry) error {
|
func (s *Server) startHealthServer() error {
|
||||||
healthAddr := s.HealthAddress
|
healthAddr := s.HealthAddress
|
||||||
if healthAddr == "" {
|
if healthAddr == "" {
|
||||||
healthAddr = defaultHealthAddr
|
healthAddr = defaultHealthAddr
|
||||||
}
|
}
|
||||||
s.healthServer = health.NewServer(healthAddr, s.healthChecker, s.Logger, promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
|
s.healthServer = health.NewServer(healthAddr, s.healthChecker, s.Logger, promhttp.HandlerFor(prometheus2.DefaultGatherer, promhttp.HandlerOpts{EnableOpenMetrics: true}))
|
||||||
healthListener, err := net.Listen("tcp", healthAddr)
|
healthListener, err := net.Listen("tcp", healthAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("health probe server listen on %s: %w", healthAddr, err)
|
return fmt.Errorf("health probe server listen on %s: %w", healthAddr, err)
|
||||||
@@ -423,7 +437,7 @@ func (s *Server) configureTLS(ctx context.Context) (*tls.Config, error) {
|
|||||||
"acme_server": s.ACMEDirectory,
|
"acme_server": s.ACMEDirectory,
|
||||||
"challenge_type": s.ACMEChallengeType,
|
"challenge_type": s.ACMEChallengeType,
|
||||||
}).Debug("ACME certificates enabled, configuring certificate manager")
|
}).Debug("ACME certificates enabled, configuring certificate manager")
|
||||||
s.acme = acme.NewManager(s.CertificateDirectory, s.ACMEDirectory, s.ACMEEABKID, s.ACMEEABHMACKey, s, s.Logger, s.CertLockMethod)
|
s.acme = acme.NewManager(s.CertificateDirectory, s.ACMEDirectory, s.ACMEEABKID, s.ACMEEABHMACKey, s, s.Logger, s.CertLockMethod, s.meter)
|
||||||
|
|
||||||
if s.ACMEChallengeType == "http-01" {
|
if s.ACMEChallengeType == "http-01" {
|
||||||
s.http = &http.Server{
|
s.http = &http.Server{
|
||||||
|
|||||||
@@ -2822,6 +2822,16 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
description: "City name from geolocation"
|
description: "City name from geolocation"
|
||||||
example: "San Francisco"
|
example: "San Francisco"
|
||||||
|
bytes_upload:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: "Bytes uploaded (request body size)"
|
||||||
|
example: 1024
|
||||||
|
bytes_download:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
description: "Bytes downloaded (response body size)"
|
||||||
|
example: 8192
|
||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
- service_id
|
- service_id
|
||||||
@@ -2831,6 +2841,8 @@ components:
|
|||||||
- path
|
- path
|
||||||
- duration_ms
|
- duration_ms
|
||||||
- status_code
|
- status_code
|
||||||
|
- bytes_upload
|
||||||
|
- bytes_download
|
||||||
ProxyAccessLogsResponse:
|
ProxyAccessLogsResponse:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.26.0
|
||||||
// protoc v6.33.3
|
// protoc v6.33.0
|
||||||
// source: management.proto
|
// source: management.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.26.0
|
||||||
// protoc v6.33.3
|
// protoc v6.33.0
|
||||||
// source: proxy_service.proto
|
// source: proxy_service.proto
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
@@ -740,6 +740,8 @@ type AccessLog struct {
|
|||||||
AuthMechanism string `protobuf:"bytes,11,opt,name=auth_mechanism,json=authMechanism,proto3" json:"auth_mechanism,omitempty"`
|
AuthMechanism string `protobuf:"bytes,11,opt,name=auth_mechanism,json=authMechanism,proto3" json:"auth_mechanism,omitempty"`
|
||||||
UserId string `protobuf:"bytes,12,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
UserId string `protobuf:"bytes,12,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||||
AuthSuccess bool `protobuf:"varint,13,opt,name=auth_success,json=authSuccess,proto3" json:"auth_success,omitempty"`
|
AuthSuccess bool `protobuf:"varint,13,opt,name=auth_success,json=authSuccess,proto3" json:"auth_success,omitempty"`
|
||||||
|
BytesUpload int64 `protobuf:"varint,14,opt,name=bytes_upload,json=bytesUpload,proto3" json:"bytes_upload,omitempty"`
|
||||||
|
BytesDownload int64 `protobuf:"varint,15,opt,name=bytes_download,json=bytesDownload,proto3" json:"bytes_download,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *AccessLog) Reset() {
|
func (x *AccessLog) Reset() {
|
||||||
@@ -865,6 +867,20 @@ func (x *AccessLog) GetAuthSuccess() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *AccessLog) GetBytesUpload() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.BytesUpload
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AccessLog) GetBytesDownload() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.BytesDownload
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type AuthenticateRequest struct {
|
type AuthenticateRequest struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
@@ -1698,7 +1714,7 @@ var file_proxy_service_proto_rawDesc = []byte{
|
|||||||
0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||||
0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x22,
|
0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x22,
|
||||||
0x17, 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67,
|
0x17, 0x0a, 0x15, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67,
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa0, 0x03, 0x0a, 0x09, 0x41, 0x63, 0x63,
|
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xea, 0x03, 0x0a, 0x09, 0x41, 0x63, 0x63,
|
||||||
0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74,
|
||||||
0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
|
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
|
||||||
@@ -1724,153 +1740,158 @@ var file_proxy_service_proto_rawDesc = []byte{
|
|||||||
0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09,
|
0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68,
|
0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x68,
|
||||||
0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b,
|
0x5f, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b,
|
||||||
0x61, 0x75, 0x74, 0x68, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x13,
|
0x61, 0x75, 0x74, 0x68, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x62,
|
||||||
0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
|
0x79, 0x74, 0x65, 0x73, 0x5f, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28,
|
||||||
0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x03, 0x52, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x55, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x25,
|
||||||
0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69,
|
0x0a, 0x0e, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64,
|
||||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
0x18, 0x0f, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x62, 0x79, 0x74, 0x65, 0x73, 0x44, 0x6f, 0x77,
|
||||||
0x49, 0x64, 0x12, 0x39, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03,
|
0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0xb6, 0x01, 0x0a, 0x13, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e,
|
||||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
|
0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a,
|
||||||
0x74, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
|
||||||
0x74, 0x48, 0x00, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x2a, 0x0a,
|
|
||||||
0x03, 0x70, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e,
|
|
||||||
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
|
||||||
0x73, 0x74, 0x48, 0x00, 0x52, 0x03, 0x70, 0x69, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71,
|
|
||||||
0x75, 0x65, 0x73, 0x74, 0x22, 0x2d, 0x0a, 0x0f, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
|
|
||||||
0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77,
|
|
||||||
0x6f, 0x72, 0x64, 0x22, 0x1e, 0x0a, 0x0a, 0x50, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
|
||||||
0x74, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
|
|
||||||
0x70, 0x69, 0x6e, 0x22, 0x55, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
|
||||||
0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73,
|
|
||||||
0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75,
|
|
||||||
0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
|
||||||
0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65,
|
|
||||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xf3, 0x01, 0x0a, 0x17, 0x53,
|
|
||||||
0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52,
|
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
|
||||||
0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76,
|
|
||||||
0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
|
||||||
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75,
|
|
||||||
0x6e, 0x74, 0x49, 0x64, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03,
|
|
||||||
0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
|
|
||||||
0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73,
|
|
||||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x0a, 0x12, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
|
|
||||||
0x63, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
|
|
||||||
0x08, 0x52, 0x11, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x49, 0x73,
|
|
||||||
0x73, 0x75, 0x65, 0x64, 0x12, 0x28, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65,
|
|
||||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x65,
|
|
||||||
0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x42, 0x10,
|
|
||||||
0x0a, 0x0e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
|
||||||
0x22, 0x1a, 0x0a, 0x18, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70,
|
|
||||||
0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb8, 0x01, 0x0a,
|
|
||||||
0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x65, 0x65, 0x72,
|
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69,
|
|
||||||
0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72,
|
|
||||||
0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e,
|
|
||||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f,
|
|
||||||
0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03,
|
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x77,
|
|
||||||
0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
|
|
||||||
0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x69, 0x72, 0x65, 0x67,
|
|
||||||
0x75, 0x61, 0x72, 0x64, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a,
|
|
||||||
0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
|
||||||
0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x22, 0x6f, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74,
|
|
||||||
0x65, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
|
||||||
0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20,
|
|
||||||
0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x0d,
|
|
||||||
0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20,
|
|
||||||
0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73,
|
|
||||||
0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72,
|
|
||||||
0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x65, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4f,
|
|
||||||
0x49, 0x44, 0x43, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a,
|
|
||||||
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a,
|
0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a,
|
||||||
0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c,
|
0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x08,
|
||||||
0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01,
|
0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
|
||||||
0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x22,
|
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x61, 0x73, 0x73,
|
||||||
0x26, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4f, 0x49, 0x44, 0x43, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73,
|
0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x08, 0x70,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01,
|
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x2a, 0x0a, 0x03, 0x70, 0x69, 0x6e, 0x18, 0x04,
|
||||||
0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x55, 0x0a, 0x16, 0x56, 0x61, 0x6c, 0x69, 0x64,
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
|
||||||
0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x74, 0x2e, 0x50, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x03,
|
||||||
0x74, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28,
|
0x70, 0x69, 0x6e, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2d,
|
||||||
0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x73,
|
0x0a, 0x0f, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20,
|
||||||
0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x8c,
|
0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x1e, 0x0a,
|
||||||
0x01, 0x0a, 0x17, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69,
|
0x0a, 0x50, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x70,
|
||||||
0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
|
0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x6e, 0x22, 0x55, 0x0a,
|
||||||
0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64,
|
0x14, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73,
|
||||||
0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||||
0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12,
|
||||||
0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75,
|
0x23, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
||||||
0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x6e, 0x69,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54,
|
||||||
0x65, 0x64, 0x5f, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xf3, 0x01, 0x0a, 0x17, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61,
|
||||||
0x0c, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0x64, 0x0a,
|
0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x16, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64,
|
0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01,
|
||||||
0x61, 0x74, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x50, 0x44, 0x41, 0x54,
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64, 0x12,
|
||||||
0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00,
|
0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
|
||||||
0x12, 0x18, 0x0a, 0x14, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f,
|
0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x2f,
|
||||||
0x4d, 0x4f, 0x44, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x50,
|
0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17,
|
||||||
0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45,
|
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x78,
|
||||||
0x44, 0x10, 0x02, 0x2a, 0x46, 0x0a, 0x0f, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x77, 0x72, 0x69,
|
0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
|
||||||
0x74, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x41, 0x54, 0x48, 0x5f, 0x52,
|
0x2d, 0x0a, 0x12, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x69,
|
||||||
0x45, 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00,
|
0x73, 0x73, 0x75, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x63, 0x65, 0x72,
|
||||||
0x12, 0x19, 0x0a, 0x15, 0x50, 0x41, 0x54, 0x48, 0x5f, 0x52, 0x45, 0x57, 0x52, 0x49, 0x54, 0x45,
|
0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x49, 0x73, 0x73, 0x75, 0x65, 0x64, 0x12, 0x28,
|
||||||
0x5f, 0x50, 0x52, 0x45, 0x53, 0x45, 0x52, 0x56, 0x45, 0x10, 0x01, 0x2a, 0xc8, 0x01, 0x0a, 0x0b,
|
0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18,
|
||||||
0x50, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x14, 0x50,
|
0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65,
|
||||||
0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44,
|
0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x65, 0x72, 0x72,
|
||||||
0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53,
|
0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x1a, 0x0a, 0x18, 0x53, 0x65,
|
||||||
0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x23,
|
0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65,
|
||||||
0x0a, 0x1f, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x54,
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb8, 0x01, 0x0a, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||||
0x55, 0x4e, 0x4e, 0x45, 0x4c, 0x5f, 0x4e, 0x4f, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45,
|
0x65, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x44, 0x10, 0x02, 0x12, 0x24, 0x0a, 0x20, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53, 0x54, 0x41,
|
0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18,
|
||||||
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x64,
|
||||||
|
0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02,
|
||||||
|
0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12,
|
||||||
|
0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
|
||||||
|
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61,
|
||||||
|
0x72, 0x64, 0x5f, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x69, 0x72, 0x65, 0x67, 0x75, 0x61, 0x72, 0x64, 0x50, 0x75,
|
||||||
|
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74,
|
||||||
|
0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65,
|
||||||
|
0x72, 0x22, 0x6f, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x78, 0x79,
|
||||||
|
0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07,
|
||||||
|
0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73,
|
||||||
|
0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f,
|
||||||
|
0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52,
|
||||||
|
0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x88, 0x01, 0x01,
|
||||||
|
0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61,
|
||||||
|
0x67, 0x65, 0x22, 0x65, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4f, 0x49, 0x44, 0x43, 0x55, 0x52, 0x4c,
|
||||||
|
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||||
|
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x6f, 0x75,
|
||||||
|
0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63,
|
||||||
|
0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65,
|
||||||
|
0x63, 0x74, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65,
|
||||||
|
0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x72, 0x6c, 0x22, 0x26, 0x0a, 0x12, 0x47, 0x65, 0x74,
|
||||||
|
0x4f, 0x49, 0x44, 0x43, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
|
0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72,
|
||||||
|
0x6c, 0x22, 0x55, 0x0a, 0x16, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73,
|
||||||
|
0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x64,
|
||||||
|
0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x6f, 0x6d,
|
||||||
|
0x61, 0x69, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74,
|
||||||
|
0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x73, 0x73,
|
||||||
|
0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x8c, 0x01, 0x0a, 0x17, 0x56, 0x61, 0x6c,
|
||||||
|
0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
|
||||||
|
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||||
|
0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73,
|
||||||
|
0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65,
|
||||||
|
0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69,
|
||||||
|
0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x75, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61,
|
||||||
|
0x69, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x6e, 0x69, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x61,
|
||||||
|
0x73, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x6e, 0x69, 0x65,
|
||||||
|
0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0x64, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x78, 0x79,
|
||||||
|
0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x79, 0x70,
|
||||||
|
0x65, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45,
|
||||||
|
0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x50,
|
||||||
|
0x44, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x4f, 0x44, 0x49, 0x46, 0x49,
|
||||||
|
0x45, 0x44, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x5f, 0x54,
|
||||||
|
0x59, 0x50, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x46, 0x0a,
|
||||||
|
0x0f, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x77, 0x72, 0x69, 0x74, 0x65, 0x4d, 0x6f, 0x64, 0x65,
|
||||||
|
0x12, 0x18, 0x0a, 0x14, 0x50, 0x41, 0x54, 0x48, 0x5f, 0x52, 0x45, 0x57, 0x52, 0x49, 0x54, 0x45,
|
||||||
|
0x5f, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x41,
|
||||||
|
0x54, 0x48, 0x5f, 0x52, 0x45, 0x57, 0x52, 0x49, 0x54, 0x45, 0x5f, 0x50, 0x52, 0x45, 0x53, 0x45,
|
||||||
|
0x52, 0x56, 0x45, 0x10, 0x01, 0x2a, 0xc8, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x53,
|
||||||
|
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53,
|
||||||
|
0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12,
|
||||||
|
0x17, 0x0a, 0x13, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f,
|
||||||
|
0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x50, 0x52, 0x4f, 0x58,
|
||||||
|
0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x54, 0x55, 0x4e, 0x4e, 0x45, 0x4c, 0x5f,
|
||||||
|
0x4e, 0x4f, 0x54, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x24, 0x0a,
|
||||||
|
0x20, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x45,
|
||||||
|
0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e,
|
||||||
|
0x47, 0x10, 0x03, 0x12, 0x23, 0x0a, 0x1f, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53, 0x54, 0x41,
|
||||||
0x54, 0x55, 0x53, 0x5f, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x5f,
|
0x54, 0x55, 0x53, 0x5f, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x5f,
|
||||||
0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x23, 0x0a, 0x1f, 0x50, 0x52, 0x4f,
|
0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x52, 0x4f, 0x58,
|
||||||
0x58, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46,
|
0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x05,
|
||||||
0x49, 0x43, 0x41, 0x54, 0x45, 0x5f, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x04, 0x12, 0x16,
|
0x32, 0xfc, 0x04, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||||
0x0a, 0x12, 0x50, 0x52, 0x4f, 0x58, 0x59, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45,
|
0x65, 0x12, 0x5f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x55,
|
||||||
0x52, 0x52, 0x4f, 0x52, 0x10, 0x05, 0x32, 0xfc, 0x04, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x78, 0x79,
|
|
||||||
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5f, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x61,
|
|
||||||
0x70, 0x70, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61,
|
|
||||||
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x70,
|
|
||||||
0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
|
||||||
0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x47, 0x65,
|
|
||||||
0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65,
|
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x54, 0x0a, 0x0d, 0x53, 0x65, 0x6e, 0x64,
|
|
||||||
0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61,
|
|
||||||
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73,
|
|
||||||
0x73, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61,
|
|
||||||
0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x63,
|
|
||||||
0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51,
|
|
||||||
0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f,
|
|
||||||
0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x75, 0x74, 0x68,
|
|
||||||
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
|
||||||
0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x75, 0x74,
|
|
||||||
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
|
||||||
0x65, 0x12, 0x5d, 0x0a, 0x10, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55,
|
|
||||||
0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65,
|
0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65,
|
||||||
0x6e, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64,
|
0x6e, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x55, 0x70, 0x64,
|
||||||
0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e,
|
0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e,
|
||||||
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74,
|
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69,
|
||||||
0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
0x6e, 0x67, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
0x12, 0x5a, 0x0a, 0x0f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50,
|
0x30, 0x01, 0x12, 0x54, 0x0a, 0x0d, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73,
|
||||||
0x65, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
0x4c, 0x6f, 0x67, 0x12, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||||
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x65, 0x65, 0x72,
|
0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67, 0x52, 0x65,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65,
|
||||||
0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x78, 0x79,
|
0x6e, 0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x6f, 0x67,
|
||||||
0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0a,
|
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x51, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68,
|
||||||
0x47, 0x65, 0x74, 0x4f, 0x49, 0x44, 0x43, 0x55, 0x52, 0x4c, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x6e,
|
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67,
|
||||||
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x49, 0x44, 0x43, 0x55,
|
0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
|
||||||
0x52, 0x4c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x6e, 0x61,
|
0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6d, 0x61, 0x6e, 0x61,
|
||||||
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x49, 0x44, 0x43, 0x55, 0x52,
|
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
||||||
0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0f, 0x56, 0x61, 0x6c,
|
0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5d, 0x0a, 0x10, 0x53,
|
||||||
0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x6d,
|
0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12,
|
||||||
0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61,
|
0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x53, 0x65, 0x6e,
|
||||||
0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71,
|
||||||
0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x56, 0x61,
|
0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
|
||||||
0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73,
|
0x74, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x70, 0x64, 0x61,
|
||||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0f, 0x43, 0x72,
|
||||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x65, 0x65, 0x72, 0x12, 0x22, 0x2e,
|
||||||
|
0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||||
|
0x65, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
|
0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x43,
|
||||||
|
0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65,
|
||||||
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4b, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4f, 0x49, 0x44,
|
||||||
|
0x43, 0x55, 0x52, 0x4c, 0x12, 0x1d, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e,
|
||||||
|
0x74, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x49, 0x44, 0x43, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x71, 0x75,
|
||||||
|
0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||||
|
0x2e, 0x47, 0x65, 0x74, 0x4f, 0x49, 0x44, 0x43, 0x55, 0x52, 0x4c, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
|
0x6e, 0x73, 0x65, 0x12, 0x5a, 0x0a, 0x0f, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53,
|
||||||
|
0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d,
|
||||||
|
0x65, 0x6e, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x53, 0x65, 0x73, 0x73,
|
||||||
|
0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6d, 0x61, 0x6e,
|
||||||
|
0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65,
|
||||||
|
0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42,
|
||||||
|
0x08, 0x5a, 0x06, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ message AccessLog {
|
|||||||
string auth_mechanism = 11;
|
string auth_mechanism = 11;
|
||||||
string user_id = 12;
|
string user_id = 12;
|
||||||
bool auth_success = 13;
|
bool auth_success = 13;
|
||||||
|
int64 bytes_upload = 14;
|
||||||
|
int64 bytes_download = 15;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AuthenticateRequest {
|
message AuthenticateRequest {
|
||||||
|
|||||||
Reference in New Issue
Block a user