Skip to content

Commit

Permalink
Merge pull request #3 from absmach/config
Browse files Browse the repository at this point in the history
NOISSUE - Structural changes
  • Loading branch information
dborovcanin authored Aug 25, 2023
2 parents 7f79ece + ed3f08c commit 43bdacd
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 277 deletions.
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ endef
$(PROGRAM): $(SOURCES)
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
go build -mod=vendor -ldflags "-s -w \
-X 'github.com/mainflux/mainflux.BuildTime=$(TIME)' \
-X 'github.com/mainflux/mainflux.Version=$(VERSION)' \
-X 'github.com/mainflux/mainflux.Commit=$(COMMIT)'" \
-X 'github.com/absmach/aproxy.BuildTime=$(TIME)' \
-X 'github.com/absmach/aproxy.Version=$(VERSION)' \
-X 'github.com/absmach/aproxy.Commit=$(COMMIT)'" \
-o ./build/$(APROXY_DOCKER_IMAGE_NAME_PREFIX)-$(PROGRAM) cmd/main.go

clean:
Expand Down
54 changes: 30 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,37 +11,43 @@ aProxy is typically deployed on-premise, in the enterprise cloud, in front of Io

## Usage
```bash
go get github.com/absmach/aproxy
cd $(GOPATH)/github.com/absmach/aproxy
git clone https://github.com/absmach/aproxy.git
cd aproxy
make
./aproxy
make docker-image
make run
```

## Configuration

The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.

| Variable | Description | Default |
|-------------------------|------------------------------------------------|-----------|
| APROXY_WS_HOST | WebSocket inbound (IN) connection host | 0.0.0.0 |
| APROXY_WS_PORT | WebSocket inbound (IN) connection port | 8080 |
| APROXY_WS_PATH | WebSocket inbound (IN) connection path | /mqtt |
| APROXY_WSS_PORT | WebSocket Secure inbound (IN) connection port | 8080 |
| APROXY_WSS_PATH | WebSocket Secure inbound (IN) connection path | /mqtt |
| APROXY_WS_TARGET_SCHEME | WebSocket Target schema | ws |
| APROXY_WS_TARGET_HOST | WebSocket Target host | localhost |
| APROXY_WS_TARGET_PORT | WebSocket Target port | 8888 |
| APROXY_WS_TARGET_PATH | WebSocket Target path | /mqtt |
| APROXY_MQTT_HOST | MQTT inbound connection host | 0.0.0.0 |
| APROXY_MQTT_PORT | MQTT inbound connection port | 1883 |
| APROXY_MQTTS_PORT | MQTTS inbound connection port | 8883 |
| APROXY_MQTT_TARGET_HOST | MQTT broker host | 0.0.0.0 |
| APROXY_MQTT_TARGET_PORT | MQTT broker port | 1884 |
| APROXY_CLIENT_TLS | Flag that indicates if TLS should be turned on | false |
| APROXY_CA_CERTS | Path to trusted CAs in PEM format | |
| APROXY_SERVER_CERT | Path to server certificate in pem format | |
| APROXY_SERVER_KEY | Path to server key in pem format | |
| APROXY_LOG_LEVEL | Log level | debug |
| Variable | Description | Default |
|---------------------------------|------------------------------------------------|-----------|
| APROXY_WS_HOST | WebSocket inbound (IN) connection host | 0.0.0.0 |
| APROXY_WS_PORT | WebSocket inbound (IN) connection port | 8080 |
| APROXY_WS_PATH | WebSocket inbound (IN) connection path | /mqtt |
| APROXY_WSS_PORT | WebSocket Secure inbound (IN) connection port | 8080 |
| APROXY_WSS_PATH | WebSocket Secure inbound (IN) connection path | /mqtt |
| APROXY_WS_TARGET_SCHEME | WebSocket Target schema | ws |
| APROXY_WS_TARGET_HOST | WebSocket Target host | localhost |
| APROXY_WS_TARGET_PORT | WebSocket Target port | 8888 |
| APROXY_WS_TARGET_PATH | WebSocket Target path | /mqtt |
| APROXY_MQTT_HOST | MQTT inbound connection host | 0.0.0.0 |
| APROXY_MQTT_PORT | MQTT inbound connection port | 1883 |
| APROXY_MQTTS_PORT | MQTTS inbound connection port | 8883 |
| APROXY_MQTT_TARGET_HOST | MQTT broker host | 0.0.0.0 |
| APROXY_MQTT_TARGET_PORT | MQTT broker port | 1884 |
| APROXY_CLIENT_TLS | Flag that indicates if TLS should be turned on | false |
| APROXY_CA_CERTS | Path to trusted CAs in PEM format | |
| APROXY_SERVER_CERT | Path to server certificate in pem format | |
| APROXY_SERVER_KEY | Path to server key in pem format | |
| APROXY_LOG_LEVEL | Log level | debug |
| APROXY_MQTT_ADAPTER_CONFIG_FILE | Config file path. This overites env if set. | |
| APROXY_RELEASE_TAG | Docker release tag. | latest |
| APROXY_THINGS_URL | Things url. | |
| APROXY_THINGS_AUTH_GRPC_URL | Things GRPC URL for authentication. | |
| APROXY_THINGS_AUTH_GRPC_TIMEOUT | Things GRPC timeout duration | 1s |

## License
[Apache-2.0](LICENSE)
Expand Down
107 changes: 15 additions & 92 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,82 +9,33 @@ import (
"os"
"time"

"github.com/absmach/aproxy"
"github.com/absmach/aproxy/auth"
thingsclient "github.com/absmach/aproxy/internal/clients/grpc/things"
"github.com/absmach/aproxy/internal/config"
thingsclient "github.com/absmach/aproxy/internal/grpc/things"
mproxy "github.com/absmach/aproxy/mqtt"
"github.com/caarlos0/env/v9"
"github.com/cenkalti/backoff/v4"
chclient "github.com/mainflux/callhome/pkg/client"
"github.com/mainflux/mainflux"
mflog "github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/pkg/errors"
mqttpub "github.com/mainflux/mainflux/pkg/messaging/mqtt"
"github.com/mainflux/mainflux/pkg/uuid"
mp "github.com/mainflux/mproxy/pkg/mqtt"
"github.com/mainflux/mproxy/pkg/session"
"github.com/mainflux/mproxy/pkg/websocket"
"github.com/pelletier/go-toml/v2"
"golang.org/x/sync/errgroup"
)

const svcName = "mqtt"

type MQTTAdapterConfig struct {
MQTTPort string `toml:"PORT" env:"APROXY_MQTT_ADAPTER_MQTT_PORT" envDefault:"1883"`
MQTTTargetHost string `toml:"TARGET_HOST" env:"APROXY_MQTT_ADAPTER_MQTT_TARGET_HOST" envDefault:"localhost"`
MQTTTargetPort string `toml:"TARGET_PORT" env:"APROXY_MQTT_ADAPTER_MQTT_TARGET_PORT" envDefault:"1883"`
MQTTForwarderTimeout Duration `toml:"FORWARDER_TIMEOUT" env:"APROXY_MQTT_ADAPTER_FORWARDER_TIMEOUT" envDefault:"30s"`
MQTTTargetHealthCheck string `toml:"HEALTH_CHECK" env:"APROXY_MQTT_ADAPTER_MQTT_TARGET_HEALTH_CHECK" envDefault:""`
}

type HTTPAdapterConfig struct {
HTTPPort string `toml:"PORT" env:"APROXY_MQTT_ADAPTER_WS_PORT" envDefault:"8080"`
HTTPTargetHost string `toml:"TARGET_HOST" env:"APROXY_MQTT_ADAPTER_WS_TARGET_HOST" envDefault:"localhost"`
HTTPTargetPort string `toml:"TARGET_PORT" env:"APROXY_MQTT_ADAPTER_WS_TARGET_PORT" envDefault:"8080"`
HTTPTargetPath string `toml:"TARGET_PATH" env:"APROXY_MQTT_ADAPTER_WS_TARGET_PATH" envDefault:"/mqtt"`
}

type GeneralConfig struct {
LogLevel string `toml:"LOG_LEVEL" env:"APROXY_MQTT_ADAPTER_LOG_LEVEL" envDefault:"info"`
Instance string `toml:"INSTANCE" env:"APROXY_MQTT_ADAPTER_INSTANCE" envDefault:""`
JaegerURL string `toml:"JAEGER_URL" env:"APROXY_JAEGER_URL" envDefault:"http://jaeger:14268/api/traces"`
SendTelemetry bool `toml:"SEND_TELEMETRY" env:"APROXY_SEND_TELEMETRY" envDefault:"true"`
InstanceID string `toml:"INSTANCE_ID" env:"APROXY_MQTT_ADAPTER_INSTANCE_ID" envDefault:""`
}

type config struct {
MQTTAdapter MQTTAdapterConfig `toml:"MQTTAdapter"`
HTTPAdapter HTTPAdapterConfig `toml:"HTTPAdapter"`
General GeneralConfig `toml:"General"`
ConfigFile string `toml:"-" env:"APROXY_MQTT_ADAPTER_CONFIG_FILE" envDefault:"config.toml"`
}

type Duration time.Duration

func (d *Duration) UnmarshalText(b []byte) error {
x, err := time.ParseDuration(string(b))
if err != nil {
return err
}
*d = Duration(x)
return nil
}
const svcName = "aproxy"

func main() {
ctx, cancel := context.WithCancel(context.Background())
g, ctx := errgroup.WithContext(ctx)

cfg := config{}
if err := env.Parse(&cfg); err != nil {
cfg, err := config.NewConfig()
if err != nil {
log.Fatalf("failed to load %s configuration : %s", svcName, err)
}

if cfg.ConfigFile != "" {
if err := parseConfigFile(&cfg); err != nil {
log.Fatalf("failed to load config file : %v", err)
}
}

logger, err := mflog.New(os.Stdout, cfg.General.LogLevel)
if err != nil {
log.Fatalf("failed to init logger: %s", err)
Expand All @@ -106,22 +57,14 @@ func main() {
logger.Info(fmt.Sprintf("Broker not ready: %s, next try in %s", e.Error(), next))
}

err := backoff.RetryNotify(healthcheck(cfg), backoff.NewExponentialBackOff(), notify)
err := backoff.RetryNotify(healthcheck(cfg.MQTTAdapter), backoff.NewExponentialBackOff(), notify)
if err != nil {
logger.Error(fmt.Sprintf("MQTT healthcheck limit exceeded, exiting. %s ", err))
exitCode = 1
return
}
}

//nps, err := brokers.NewPubSub(cfg.General.BrokerURL, "mqtt", logger)
if err != nil {
logger.Error(fmt.Sprintf("failed to connect to message broker: %s", err))
exitCode = 1
return
}
//defer nps.Close()

mpub, err := mqttpub.NewPublisher(fmt.Sprintf("%s:%s", cfg.MQTTAdapter.MQTTTargetHost, cfg.MQTTAdapter.MQTTTargetPort), time.Duration(cfg.MQTTAdapter.MQTTForwarderTimeout))
if err != nil {
logger.Error(fmt.Sprintf("failed to create MQTT publisher: %s", err))
Expand All @@ -144,14 +87,9 @@ func main() {

h := mproxy.NewHandler(logger, authClient)

if cfg.General.SendTelemetry {
chc := chclient.New(svcName, mainflux.Version, logger, cancel)
go chc.CallHome(ctx)
}

logger.Info(fmt.Sprintf("Starting MQTT proxy on port %s", cfg.MQTTAdapter.MQTTPort))
g.Go(func() error {
return proxyMQTT(ctx, cfg, logger, h)
return proxyMQTT(ctx, cfg.MQTTAdapter, logger, h)
})

logger.Info(fmt.Sprintf("Starting MQTT over WS proxy on port %s", cfg.HTTPAdapter.HTTPPort))
Expand All @@ -172,9 +110,9 @@ func main() {
}
}

func proxyMQTT(ctx context.Context, cfg config, logger mflog.Logger, handler session.Handler) error {
address := fmt.Sprintf(":%s", cfg.MQTTAdapter.MQTTPort)
target := fmt.Sprintf("%s:%s", cfg.MQTTAdapter.MQTTTargetHost, cfg.MQTTAdapter.MQTTTargetPort)
func proxyMQTT(ctx context.Context, cfg config.MQTTAdapterConfig, logger mflog.Logger, handler session.Handler) error {
address := fmt.Sprintf(":%s", cfg.MQTTPort)
target := fmt.Sprintf("%s:%s", cfg.MQTTTargetHost, cfg.MQTTTargetPort)
mp := mp.New(address, target, handler, logger)

errCh := make(chan error)
Expand All @@ -191,10 +129,11 @@ func proxyMQTT(ctx context.Context, cfg config, logger mflog.Logger, handler ses
}
}

func proxyWS(ctx context.Context, cfg config, logger mflog.Logger, handler session.Handler) error {
func proxyWS(ctx context.Context, cfg config.Config, logger mflog.Logger, handler session.Handler) error {
target := fmt.Sprintf("%s:%s", cfg.HTTPAdapter.HTTPTargetHost, cfg.HTTPAdapter.HTTPTargetPort)
wp := websocket.New(target, cfg.HTTPAdapter.HTTPTargetPath, "ws", handler, logger)
http.Handle("/mqtt", wp.Handler())
http.Handle("/health", aproxy.Health(svcName, cfg.General.InstanceID))

errCh := make(chan error)

Expand All @@ -211,9 +150,9 @@ func proxyWS(ctx context.Context, cfg config, logger mflog.Logger, handler sessi
}
}

func healthcheck(cfg config) func() error {
func healthcheck(cfg config.MQTTAdapterConfig) func() error {
return func() error {
res, err := http.Get(cfg.MQTTAdapter.MQTTTargetHealthCheck)
res, err := http.Get(cfg.MQTTTargetHealthCheck)
if err != nil {
return err
}
Expand All @@ -228,19 +167,3 @@ func healthcheck(cfg config) func() error {
return nil
}
}

func parseConfigFile(cfg *config) error {
file, err := os.Open(cfg.ConfigFile)
if err != nil {
return err
}
fileData, err := io.ReadAll(file)
if err != nil {
return err
}
if err := toml.Unmarshal(fileData, cfg); err != nil {
return err
}

return nil
}
1 change: 0 additions & 1 deletion configs/config.toml → config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@
[General]
INSTANCE = ""
JAEGER_URL = "http://jaeger:14268/api/traces"
SEND_TELEMETRY = false
INSTANCE_ID = ""
LOG_LEVEL = "debug"
3 changes: 0 additions & 3 deletions docker/.env
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@ APROXY_MQTT_ADAPTER_WS_TARGET_HOST=vernemq
APROXY_MQTT_ADAPTER_WS_TARGET_PORT=8080
APROXY_MQTT_ADAPTER_WS_TARGET_PATH=/mqtt
APROXY_MQTT_ADAPTER_INSTANCE=
APROXY_MQTT_ADAPTER_ES_URL=es-redis:${APROXY_REDIS_TCP_PORT}
APROXY_MQTT_ADAPTER_ES_PASS=
APROXY_MQTT_ADAPTER_INSTANCE_ID=
APROXY_MQTT_ADAPTER_ES_DB=0
APROXY_MQTT_ADAPTER_CONFIG_FILE="config.toml"

# Docker image tag
Expand Down
9 changes: 4 additions & 5 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@ services:
APROXY_MQTT_ADAPTER_WS_TARGET_PORT: ${APROXY_MQTT_ADAPTER_WS_TARGET_PORT}
APROXY_MQTT_ADAPTER_WS_TARGET_PATH: ${APROXY_MQTT_ADAPTER_WS_TARGET_PATH}
APROXY_MQTT_ADAPTER_INSTANCE: ${APROXY_MQTT_ADAPTER_INSTANCE}
APROXY_MQTT_ADAPTER_ES_URL: ${APROXY_MQTT_ADAPTER_ES_URL}
APROXY_MQTT_ADAPTER_ES_PASS: ${APROXY_MQTT_ADAPTER_ES_PASS}
APROXY_MQTT_ADAPTER_ES_DB: ${APROXY_MQTT_ADAPTER_ES_DB}
APROXY_THINGS_AUTH_GRPC_URL: ${APROXY_THINGS_AUTH_GRPC_URL}
APROXY_THINGS_AUTH_GRPC_TIMEOUT: ${APROXY_THINGS_AUTH_GRPC_TIMEOUT}
APROXY_THINGS_AUTH_GRPC_CLIENT_TLS: ${APROXY_THINGS_AUTH_GRPC_CLIENT_TLS}
APROXY_THINGS_AUTH_GRPC_CA_CERTS: ${APROXY_THINGS_AUTH_GRPC_CA_CERTS}
APROXY_JAEGER_URL: ${APROXY_JAEGER_URL}
APROXY_SEND_TELEMETRY: ${APROXY_SEND_TELEMETRY}
networks:
- mainflux-base-net
volumes:
- ../configs/config.toml:/config.toml
- ../config.toml:/config.toml
ports:
- ${APROXY_MQTT_ADAPTER_WS_TARGET_PORT}:${APROXY_MQTT_ADAPTER_WS_TARGET_PORT}

8 changes: 6 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ go 1.21.0
require (
github.com/caarlos0/env/v9 v9.0.0
github.com/cenkalti/backoff/v4 v4.2.1
github.com/mainflux/callhome v0.0.0-20230626140149-b03b1f4c46f2
github.com/mainflux/mainflux v0.12.0
github.com/mainflux/mproxy v0.3.1-0.20230822124450-4b4dfe600cc2
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0
Expand All @@ -14,7 +13,12 @@ require (
)

require (
github.com/caarlos0/env/v7 v7.1.0 // indirect
github.com/jackc/pgconn v1.14.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.2 // indirect
)

require (
github.com/caarlos0/env/v7 v7.1.0
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/eclipse/paho.mqtt.golang v1.4.2 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
Expand Down
5 changes: 2 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZ
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
Expand Down Expand Up @@ -172,8 +171,6 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mainflux/callhome v0.0.0-20230626140149-b03b1f4c46f2 h1:QN+yhU6Twwwwz8Mu9u12f2TbPsmM/zIvndAhH1dIdWU=
github.com/mainflux/callhome v0.0.0-20230626140149-b03b1f4c46f2/go.mod h1:q4cTH8I3Y6kDyocJh5dBppuv4dY9drb/2kVdB6FP124=
github.com/mainflux/mainflux v0.0.0-20230823124803-822a607e31fe h1:galNZWS6B/O0TM8ByATkpXgTTO18lpOmjmxZ9y0kNXg=
github.com/mainflux/mainflux v0.0.0-20230823124803-822a607e31fe/go.mod h1:cHi+VUm+VST3OaROF0W34pqtr7DHOhrjJ3PDNBTI5W4=
github.com/mainflux/mproxy v0.3.1-0.20230822124450-4b4dfe600cc2 h1:D5Ofrffx/4FWehczvJbmzD8lfcOkxcIS4XZE/fwl4mo=
Expand Down Expand Up @@ -244,6 +241,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
Expand Down Expand Up @@ -285,6 +283,7 @@ golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
Expand Down
Loading

0 comments on commit 43bdacd

Please sign in to comment.