mirror of
https://github.com/mainflux/mainflux.git
synced 2025-04-24 13:48:49 +08:00
MF-415 - Merge mProxy support (#1045)
* NOISSUE - Add mProxy support (#1017) * Add mproxy Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> * Fix docker and add EMQ compose Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> * Fix EMQX name Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> * Add nats, auth and es Signed-off-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> * Removed unucessary vendoring Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com> * Update vendoring Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com> * Fix mproxy interface implementation Signed-off-by: Drasko Draskovic <drasko.draskovic@gmail.com> NOISSUE - Aligned Event interface method signatures with new spec (#1025) * Aligned Event interface method signatures with new spec Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> * Updated deps Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> NOISSUE - Update mproxy dependency (#1038) Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Update Vendor with new mProxy (#1043) Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> Twins merge conflict reverted Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Twins merge conflict reverted Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Twins fixed nats import Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Update deps Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> * Resolved GolangCI remarks Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Resolved GolangCI remarks Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> Resolved GolangCI remarks Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> * Fixed Event interface Unsubscribe() typo Signed-off-by: Nikola Marcetic <n.marcetic86@gmail.com> * Update vendors Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> * Upgrade CI script Signed-off-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com> Co-authored-by: Drasko DRASKOVIC <drasko.draskovic@gmail.com> Co-authored-by: Dušan Borovčanin <dusan.borovcanin@mainflux.com>
This commit is contained in:
parent
3b5d51276f
commit
42b3682352
2
Makefile
2
Makefile
@ -4,7 +4,7 @@
|
||||
BUILD_DIR = build
|
||||
SERVICES = users things http ws coap lora influxdb-writer influxdb-reader mongodb-writer \
|
||||
mongodb-reader cassandra-writer cassandra-reader postgres-writer postgres-reader cli \
|
||||
bootstrap opcua authn twins
|
||||
bootstrap opcua authn twins mproxy
|
||||
DOCKERS = $(addprefix docker_,$(SERVICES))
|
||||
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
|
||||
CGO_ENABLED ?= 0
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/mainflux/mainflux/authn/postgres"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
const wrong string = "wrong-value"
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/mainflux/mainflux/bootstrap/postgres"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
"github.com/mainflux/mainflux/writers"
|
||||
"github.com/mainflux/mainflux/writers/api"
|
||||
"github.com/mainflux/mainflux/writers/cassandra"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
|
@ -29,7 +29,7 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
|
||||
broker "github.com/nats-io/go-nats"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -24,7 +24,7 @@ import (
|
||||
"github.com/mainflux/mainflux/http/nats"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
thingsapi "github.com/mainflux/mainflux/things/api/auth/grpc"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
jconfig "github.com/uber/jaeger-client-go/config"
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"github.com/mainflux/mainflux/writers"
|
||||
"github.com/mainflux/mainflux/writers/api"
|
||||
"github.com/mainflux/mainflux/writers/influxdb"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
"github.com/mainflux/mainflux/lora/redis"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"github.com/mainflux/mainflux/writers"
|
||||
"github.com/mainflux/mainflux/writers/api"
|
||||
"github.com/mainflux/mainflux/writers/mongodb"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
227
cmd/mproxy/main.go
Normal file
227
cmd/mproxy/main.go
Normal file
@ -0,0 +1,227 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
mqtt "github.com/mainflux/mainflux/mqtt/mproxy"
|
||||
"github.com/mainflux/mainflux/mqtt/mproxy/nats"
|
||||
mr "github.com/mainflux/mainflux/mqtt/mproxy/redis"
|
||||
thingsapi "github.com/mainflux/mainflux/things/api/auth/grpc"
|
||||
"github.com/mainflux/mproxy/pkg/events"
|
||||
mp "github.com/mainflux/mproxy/pkg/mqtt"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
jconfig "github.com/uber/jaeger-client-go/config"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
const (
|
||||
defMQTTHost = "0.0.0.0"
|
||||
defMQTTPort = "1883"
|
||||
defMQTTTargetHost = "0.0.0.0"
|
||||
defMQTTTargetPort = "1884"
|
||||
envMQTTHost = "MF_MQTT_ADAPTER_MQTT_HOST"
|
||||
envMQTTPort = "MF_MQTT_ADAPTER_MQTT_PORT"
|
||||
envMQTTTargetHost = "MF_MQTT_ADAPTER_MQTT_TARGET_HOST"
|
||||
envMQTTTargetPort = "MF_MQTT_ADAPTER_MQTT_TARGET_PORT"
|
||||
defLogLevel = "error"
|
||||
envLogLevel = "MF_MQTT_ADAPTER_LOG_LEVEL"
|
||||
defThingsURL = "localhost:8181"
|
||||
defThingsTimeout = "1" // in seconds
|
||||
envThingsURL = "MF_THINGS_URL"
|
||||
envThingsTimeout = "MF_MQTT_ADAPTER_THINGS_TIMEOUT"
|
||||
defNatsURL = broker.DefaultURL
|
||||
envNatsURL = "MF_NATS_URL"
|
||||
defJaegerURL = ""
|
||||
envJaegerURL = "MF_JAEGER_URL"
|
||||
defClientTLS = "false"
|
||||
defCACerts = ""
|
||||
envClientTLS = "MF_MQTT_ADAPTER_CLIENT_TLS"
|
||||
envCACerts = "MF_MQTT_ADAPTER_CA_CERTS"
|
||||
envInstance = "MF_MQTT_ADAPTER_INSTANCE"
|
||||
defInstance = ""
|
||||
envESURL = "MF_MQTT_ADAPTER_ES_URL"
|
||||
envESPass = "MF_MQTT_ADAPTER_ES_PASS"
|
||||
envESDB = "MF_MQTT_ADAPTER_ES_DB"
|
||||
defESURL = "localhost:6379"
|
||||
defESPass = ""
|
||||
defESDB = "0"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
mqttHost string
|
||||
mqttPort string
|
||||
mqttTargetHost string
|
||||
mqttTargetPort string
|
||||
jaegerURL string
|
||||
logLevel string
|
||||
thingsURL string
|
||||
thingsTimeout time.Duration
|
||||
natsURL string
|
||||
clientTLS bool
|
||||
caCerts string
|
||||
instance string
|
||||
esURL string
|
||||
esPass string
|
||||
esDB string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := loadConfig()
|
||||
|
||||
logger, err := logger.New(os.Stdout, cfg.logLevel)
|
||||
if err != nil {
|
||||
log.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
nc, err := broker.Connect(cfg.natsURL)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to NATS: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
defer nc.Close()
|
||||
|
||||
conn := connectToThings(cfg, logger)
|
||||
defer conn.Close()
|
||||
|
||||
tracer, closer := initJaeger("mproxy", cfg.jaegerURL, logger)
|
||||
defer closer.Close()
|
||||
|
||||
thingsTracer, thingsCloser := initJaeger("things", cfg.jaegerURL, logger)
|
||||
defer thingsCloser.Close()
|
||||
|
||||
cc := thingsapi.NewClient(conn, thingsTracer, cfg.thingsTimeout)
|
||||
pub := nats.NewMessagePublisher(nc)
|
||||
|
||||
rc := connectToRedis(cfg.esURL, cfg.esPass, cfg.esDB, logger)
|
||||
defer rc.Close()
|
||||
|
||||
es := mr.NewEventStore(rc, cfg.instance)
|
||||
|
||||
// Event handler for MQTT hooks
|
||||
evt := mqtt.New(cc, pub, es, logger, tracer)
|
||||
|
||||
errs := make(chan error, 2)
|
||||
|
||||
logger.Info(fmt.Sprintf("Starting MQTT proxy on port %s ", cfg.mqttPort))
|
||||
go proxyMQTT(cfg, logger, evt, errs)
|
||||
|
||||
go func() {
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Notify(c, syscall.SIGINT)
|
||||
errs <- fmt.Errorf("%s", <-c)
|
||||
}()
|
||||
|
||||
err = <-errs
|
||||
logger.Error(fmt.Sprintf("mProxy terminated: %s", err))
|
||||
}
|
||||
|
||||
func loadConfig() config {
|
||||
tls, err := strconv.ParseBool(mainflux.Env(envClientTLS, defClientTLS))
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid value passed for %s\n", envClientTLS)
|
||||
}
|
||||
|
||||
timeout, err := strconv.ParseInt(mainflux.Env(envThingsTimeout, defThingsTimeout), 10, 64)
|
||||
if err != nil {
|
||||
log.Fatalf("Invalid %s value: %s", envThingsTimeout, err.Error())
|
||||
}
|
||||
|
||||
return config{
|
||||
mqttHost: mainflux.Env(envMQTTHost, defMQTTHost),
|
||||
mqttPort: mainflux.Env(envMQTTPort, defMQTTPort),
|
||||
mqttTargetHost: mainflux.Env(envMQTTTargetHost, defMQTTTargetHost),
|
||||
mqttTargetPort: mainflux.Env(envMQTTTargetPort, defMQTTTargetPort),
|
||||
jaegerURL: mainflux.Env(envJaegerURL, defJaegerURL),
|
||||
thingsTimeout: time.Duration(timeout) * time.Second,
|
||||
thingsURL: mainflux.Env(envThingsURL, defThingsURL),
|
||||
natsURL: mainflux.Env(envNatsURL, defNatsURL),
|
||||
logLevel: mainflux.Env(envLogLevel, defLogLevel),
|
||||
clientTLS: tls,
|
||||
caCerts: mainflux.Env(envCACerts, defCACerts),
|
||||
instance: mainflux.Env(envInstance, defInstance),
|
||||
esURL: mainflux.Env(envESURL, defESURL),
|
||||
esPass: mainflux.Env(envESPass, defESPass),
|
||||
esDB: mainflux.Env(envESDB, defESDB),
|
||||
}
|
||||
}
|
||||
|
||||
func initJaeger(svcName, url string, logger logger.Logger) (opentracing.Tracer, io.Closer) {
|
||||
if url == "" {
|
||||
return opentracing.NoopTracer{}, ioutil.NopCloser(nil)
|
||||
}
|
||||
|
||||
tracer, closer, err := jconfig.Configuration{
|
||||
ServiceName: svcName,
|
||||
Sampler: &jconfig.SamplerConfig{
|
||||
Type: "const",
|
||||
Param: 1,
|
||||
},
|
||||
Reporter: &jconfig.ReporterConfig{
|
||||
LocalAgentHostPort: url,
|
||||
LogSpans: true,
|
||||
},
|
||||
}.NewTracer()
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to init Jaeger client: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return tracer, closer
|
||||
}
|
||||
|
||||
func connectToThings(cfg config, logger logger.Logger) *grpc.ClientConn {
|
||||
var opts []grpc.DialOption
|
||||
if cfg.clientTLS {
|
||||
if cfg.caCerts != "" {
|
||||
tpc, err := credentials.NewClientTLSFromFile(cfg.caCerts, "")
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to load certs: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
opts = append(opts, grpc.WithTransportCredentials(tpc))
|
||||
}
|
||||
} else {
|
||||
logger.Info("gRPC communication is not encrypted")
|
||||
opts = append(opts, grpc.WithInsecure())
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(cfg.thingsURL, opts...)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to things service: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
return conn
|
||||
}
|
||||
|
||||
func connectToRedis(redisURL, redisPass, redisDB string, logger logger.Logger) *redis.Client {
|
||||
db, err := strconv.Atoi(redisDB)
|
||||
if err != nil {
|
||||
logger.Error(fmt.Sprintf("Failed to connect to redis: %s", err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return redis.NewClient(&redis.Options{
|
||||
Addr: redisURL,
|
||||
Password: redisPass,
|
||||
DB: db,
|
||||
})
|
||||
}
|
||||
|
||||
func proxyMQTT(cfg config, logger logger.Logger, evt events.Event, errs chan error) {
|
||||
mp := mp.New(cfg.mqttHost, cfg.mqttPort, cfg.mqttTargetHost, cfg.mqttTargetPort, evt, logger)
|
||||
|
||||
errs <- mp.Proxy()
|
||||
}
|
@ -24,7 +24,7 @@ import (
|
||||
"github.com/mainflux/mainflux/opcua/redis"
|
||||
|
||||
kitprometheus "github.com/go-kit/kit/metrics/prometheus"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"github.com/mainflux/mainflux/writers"
|
||||
"github.com/mainflux/mainflux/writers/api"
|
||||
"github.com/mainflux/mainflux/writers/postgres"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
natspub "github.com/mainflux/mainflux/twins/nats/publisher"
|
||||
natssub "github.com/mainflux/mainflux/twins/nats/subscriber"
|
||||
"github.com/mainflux/mainflux/twins/uuid"
|
||||
nats "github.com/nats-io/go-nats"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
jconfig "github.com/uber/jaeger-client-go/config"
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
adapter "github.com/mainflux/mainflux/ws"
|
||||
"github.com/mainflux/mainflux/ws/api"
|
||||
"github.com/mainflux/mainflux/ws/nats"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
stdprometheus "github.com/prometheus/client_golang/prometheus"
|
||||
jconfig "github.com/uber/jaeger-client-go/config"
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/coap"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const prefix = "channel"
|
||||
|
47
docker/mproxy.yml
Normal file
47
docker/mproxy.yml
Normal file
@ -0,0 +1,47 @@
|
||||
# Copyright (c) Mainflux
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
version: "3.7"
|
||||
|
||||
volumes:
|
||||
mainflux-mqtt-redis-volume:
|
||||
|
||||
services:
|
||||
nginx:
|
||||
depends_on:
|
||||
- mqtt-adapter
|
||||
|
||||
emqx:
|
||||
image: emqx/emqx:latest
|
||||
container_name: mainflux-emqx
|
||||
restart: on-failure
|
||||
environment:
|
||||
EMQX_LISTENER__TCP__EXTERNAL: 1884
|
||||
ports:
|
||||
- 1884:1884
|
||||
networks:
|
||||
- mainflux-base-net
|
||||
|
||||
mqtt-adapter:
|
||||
image: mainflux/mproxy:latest
|
||||
container_name: mainflux-mqtt
|
||||
depends_on:
|
||||
- emqx
|
||||
- things
|
||||
- nats
|
||||
restart: on-failure
|
||||
environment:
|
||||
MF_MQTT_ADAPTER_LOG_LEVEL: ${MF_MQTT_ADAPTER_LOG_LEVEL}
|
||||
MF_MQTT_ADAPTER_PORT: ${MF_MQTT_ADAPTER_PORT}
|
||||
MF_MQTT_ADAPTER_WS_PORT: ${MF_MQTT_ADAPTER_WS_PORT}
|
||||
MF_MQTT_ADAPTER_ES_HOST: es-redis
|
||||
MF_NATS_URL: ${MF_NATS_URL}
|
||||
MF_THINGS_URL: things:${MF_THINGS_AUTH_GRPC_PORT}
|
||||
MF_JAEGER_URL: ${MF_JAEGER_URL}
|
||||
MF_MQTT_ADAPTER_MQTT_TARGET_HOST: emqx
|
||||
MF_MQTT_ADAPTER_MQTT_TARGET_PORT: 1884
|
||||
ports:
|
||||
- 18831:${MF_MQTT_ADAPTER_PORT}
|
||||
- 8881:${MF_MQTT_ADAPTER_WS_PORT}
|
||||
networks:
|
||||
- mainflux-base-net
|
55
go.mod
55
go.mod
@ -3,68 +3,51 @@ module github.com/mainflux/mainflux
|
||||
go 1.11
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/Microsoft/go-winio v0.4.7 // indirect
|
||||
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
|
||||
github.com/VividCortex/gohistogram v1.0.0 // indirect
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible // indirect
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
||||
github.com/containerd/continuity v0.0.0-20180416230128-c6cef3483023 // indirect
|
||||
github.com/bitly/go-hostpool v0.1.0 // indirect
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/docker/docker v1.13.1
|
||||
github.com/docker/go-connections v0.3.0 // indirect
|
||||
github.com/docker/go-units v0.3.3 // indirect
|
||||
github.com/dustin/go-coap v0.0.0-20170214053734-ddcc80675fa4
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/go-kit/kit v0.9.0
|
||||
github.com/go-redis/redis v6.15.0+incompatible
|
||||
github.com/go-zoo/bone v1.3.0
|
||||
github.com/gobuffalo/packr v1.30.1 // indirect
|
||||
github.com/gocql/gocql v0.0.0-20181106112037-68ae1e384be4
|
||||
github.com/gofrs/uuid v3.2.0+incompatible
|
||||
github.com/gogo/protobuf v1.3.1
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
|
||||
github.com/golang/protobuf v1.3.3
|
||||
github.com/gopcua/opcua v0.1.6
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible // indirect
|
||||
github.com/hokaccha/go-prettyjson v0.0.0-20180920040306-f579f869bbfe
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/influxdata/influxdb v1.6.4
|
||||
github.com/jmoiron/sqlx v1.2.1-0.20190319043955-cdf62fdf55f6
|
||||
github.com/lib/pq v1.0.0
|
||||
github.com/mainflux/mproxy v0.1.0
|
||||
github.com/mainflux/senml v1.0.0
|
||||
github.com/mattn/go-colorable v0.0.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.3 // indirect
|
||||
github.com/nats-io/gnatsd v1.4.1 // indirect
|
||||
github.com/nats-io/go-nats v1.6.0
|
||||
github.com/nats-io/nuid v1.0.0 // indirect
|
||||
github.com/onsi/ginkgo v1.10.3 // indirect
|
||||
github.com/onsi/gomega v1.7.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.1 // indirect
|
||||
github.com/opencontainers/runc v0.1.1 // indirect
|
||||
github.com/nats-io/nats-server/v2 v2.1.4 // indirect
|
||||
github.com/nats-io/nats.go v1.9.1
|
||||
github.com/opentracing/opentracing-go v1.1.0
|
||||
github.com/ory/dockertest v3.3.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml v1.4.0 // indirect
|
||||
github.com/prometheus/client_golang v0.9.3
|
||||
github.com/rubenv/sql-migrate v0.0.0-20181106121204-ba2c6a7295c5
|
||||
github.com/sony/gobreaker v0.0.0-20180905101324-b2a34562d02c
|
||||
github.com/spf13/afero v1.2.2 // indirect
|
||||
github.com/spf13/cobra v0.0.3
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/viper v1.5.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/tidwall/pretty v1.0.0 // indirect
|
||||
github.com/uber/jaeger-client-go v2.16.0+incompatible
|
||||
github.com/uber/jaeger-lib v2.0.0+incompatible // indirect
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
|
||||
github.com/xdg/stringprep v1.0.1-0.20180714160509-73f8eece6fdc // indirect
|
||||
github.com/uber/jaeger-client-go v2.22.1+incompatible
|
||||
github.com/ziutek/mymysql v1.5.4 // indirect
|
||||
go.mongodb.org/mongo-driver v1.1.3
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
gonum.org/v1/gonum v0.0.0-20190808205415-ced62fe5104b
|
||||
google.golang.org/grpc v1.24.0
|
||||
gopkg.in/gorp.v1 v1.7.1 // indirect
|
||||
gopkg.in/ory-am/dockertest.v3 v3.3.2
|
||||
google.golang.org/genproto v0.0.0-20200225123651-fc8f55426688 // indirect
|
||||
google.golang.org/grpc v1.27.1
|
||||
gopkg.in/ory/dockertest.v3 v3.3.5
|
||||
gotest.tools v2.2.0+incompatible // indirect
|
||||
)
|
||||
|
137
go.sum
137
go.sum
@ -17,11 +17,14 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bitly/go-hostpool v0.1.0 h1:XKmsF6k5el6xHG3WPJ8U0Ku/ye7njX7W81Ng7O2ioR0=
|
||||
github.com/bitly/go-hostpool v0.1.0/go.mod h1:4gOCgp6+NZnVqlKyZ/iBZFTAJKembaVENUpMkpg42fw=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible h1:5IIPUHhlnUZbcHQsQou5k1Tn58nJkeJL9U+ig5CHJbY=
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cisco/senml v0.0.0-20181031221301-910a55054e16 h1:gVMpF6unIWOG8JgCt3XhlYdT3lRFDcMMVJdMesU+TQY=
|
||||
github.com/cisco/senml v0.0.0-20181031221301-910a55054e16/go.mod h1:pLFASTQEf1nGfvoMwxmOjLeImwMKQMx18w38UcI9ZfI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w=
|
||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
|
||||
@ -29,9 +32,11 @@ github.com/containerd/continuity v0.0.0-20180416230128-c6cef3483023 h1:ydDbSX89i
|
||||
github.com/containerd/continuity v0.0.0-20180416230128-c6cef3483023/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -48,6 +53,8 @@ github.com/dustin/go-coap v0.0.0-20170214053734-ddcc80675fa4 h1:+3t0PiNl/W3Cl4/+
|
||||
github.com/dustin/go-coap v0.0.0-20170214053734-ddcc80675fa4/go.mod h1:as2rZ2aojRzZF8bGx1bPAn1yi9ICG6LwkiPOj6PBtjc=
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0=
|
||||
github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
@ -56,7 +63,6 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||
github.com/fxamacker/cbor v1.3.2 h1:jMCvPyzpTVWoe1jRDUFPupVoV+DzDvnc1VP+9VU4ql8=
|
||||
github.com/fxamacker/cbor v1.3.2/go.mod h1:Uy2lR31/2WfmW0yiA4i3t+we5kF3B/wzKsttcux+i/g=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-kit/kit v0.7.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.8.0 h1:Wz+5lgoB0kkuqLEc6NVmwRknTKP6dTGbSqvhZtBI/j0=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
|
||||
@ -68,13 +74,18 @@ github.com/go-redis/redis v6.15.0+incompatible h1:/Wib9cA7CF3SQxBZRMHyQvqzlwzc8P
|
||||
github.com/go-redis/redis v6.15.0+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
|
||||
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.7.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-zoo/bone v0.0.0-20160911183509-fd0aebc74e90 h1:r19yr6hoJJ+0ANoSBJn98J3ONZFfB4CwvrtYxRdQVeo=
|
||||
github.com/go-zoo/bone v0.0.0-20160911183509-fd0aebc74e90/go.mod h1:oqsroXM1ZcoSPNsxaSy2JNMJMSC/A463LSB0Vnoa2SI=
|
||||
github.com/go-zoo/bone v1.3.0 h1:PY6sHq37FnQhj+4ZyqFIzJQHvrrGx0GEc3vTZZC/OsI=
|
||||
github.com/go-zoo/bone v1.3.0/go.mod h1:HI3Lhb7G3UQcAwEhOJ2WyNcsFtQX1WYHa0Hl4OBbhW8=
|
||||
github.com/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU=
|
||||
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
|
||||
github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
|
||||
github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
|
||||
github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
|
||||
github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wKg=
|
||||
github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk=
|
||||
github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw=
|
||||
github.com/gocql/gocql v0.0.0-20181106112037-68ae1e384be4 h1:n5NlV76GU6337XT+jarynqONI5LlqaYkTPaFZ25og6g=
|
||||
github.com/gocql/gocql v0.0.0-20181106112037-68ae1e384be4/go.mod h1:4Fw1eo5iaEhDUs8XyuhSVCVy52Jq3L+/3GJgYkwc+/0=
|
||||
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
|
||||
@ -92,17 +103,23 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gopcua/opcua v0.1.6 h1:B9SVRKQGzcWcwP2QPYN93Uku32+3wL+v5cgzBxE6V5I=
|
||||
github.com/gopcua/opcua v0.1.6/go.mod h1:INwnDoRxmNWAt7+tzqxuGqQkSF2c1C69VAL0c2q6AcY=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI=
|
||||
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
@ -120,29 +137,34 @@ github.com/influxdata/influxdb v1.6.4 h1:K8wPlkrP02HzHTJbbUQQ1CZ2Hw6LtpG4xbNEgnl
|
||||
github.com/influxdata/influxdb v1.6.4/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
|
||||
github.com/jmoiron/sqlx v1.2.1-0.20190319043955-cdf62fdf55f6 h1:6KHlj0TRbiafVOoCXCixS0GbdWF/paU373ABxEzhY6s=
|
||||
github.com/jmoiron/sqlx v1.2.1-0.20190319043955-cdf62fdf55f6/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mainflux/senml v0.0.0-20191128185934-061491bfd7d6 h1:l5qGnZOGbiVnuclQYib6QiiQ2wA0k5vRdVdiJrTUsjw=
|
||||
github.com/mainflux/senml v0.0.0-20191128185934-061491bfd7d6/go.mod h1:g9i8pj4WMs29KkUpXivbe/PP0qJd1kt3b1CF77S8A3s=
|
||||
github.com/mainflux/senml v0.0.0-20191129155045-8e0c95e00589 h1:xoR2XyJGqBlReRXzABImJobL6l1CkgdUfJxQANvAq6A=
|
||||
github.com/mainflux/senml v0.0.0-20191129155045-8e0c95e00589/go.mod h1:g9i8pj4WMs29KkUpXivbe/PP0qJd1kt3b1CF77S8A3s=
|
||||
github.com/mainflux/mainflux v0.0.0-20191223163044-f42f2095bab4/go.mod h1:K3ghSIpAqwv5F/t30LO57+11S7tE97ur2Z6wWEHa2CA=
|
||||
github.com/mainflux/mproxy v0.1.0 h1:h6zLgLW25+hURhvmlX5HIQIRKu4p/YJkptcsgcAhwis=
|
||||
github.com/mainflux/mproxy v0.1.0/go.mod h1:HrT+8h62rGLkFDmaOoPg5CLgEURlvPfT3jr/q5y/Qw0=
|
||||
github.com/mainflux/senml v1.0.0 h1:oLS5aBhvdHjgQ8kfq3jX7yD+DaquhvpyvIWNsPil3X0=
|
||||
github.com/mainflux/senml v1.0.0/go.mod h1:g9i8pj4WMs29KkUpXivbe/PP0qJd1kt3b1CF77S8A3s=
|
||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||
@ -151,18 +173,30 @@ github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.0/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/gnatsd v1.4.1 h1:RconcfDeWpKCD6QIIwiVFcvForlXpWeJP7i5/lDLy44=
|
||||
github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ=
|
||||
github.com/nats-io/go-nats v1.6.0 h1:FznPwMfrVwGnSCh7JTXyJDRW0TIkD4Tr+M1LPJt9T70=
|
||||
github.com/nats-io/go-nats v1.6.0/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0=
|
||||
github.com/nats-io/jwt v0.3.0 h1:xdnzwFETV++jNc4W1mw//qFyJGb2ABOombmZJQS4+Qo=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server/v2 v2.1.4 h1:BILRnsJ2Yb/fefiFbBWADpViGF69uh4sxe8poVDQ06g=
|
||||
github.com/nats-io/nats-server/v2 v2.1.4/go.mod h1:Jw1Z28soD/QasIA2uWjXyM9El1jly3YwyFOuR8tH1rg=
|
||||
github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.0 h1:44QGdhbiANq8ZCbUkdn6W5bqtg+mHuDE4wOUuxxndFs=
|
||||
github.com/nats-io/nuid v1.0.0/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
|
||||
@ -179,6 +213,7 @@ github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsq
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/ory/dockertest v3.3.0+incompatible h1:r+Us+ELHPI8CudFL+l/wr7CrG6phWQ8jaqX0Sgx+OF0=
|
||||
github.com/ory/dockertest v3.3.0+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
|
||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
|
||||
@ -191,25 +226,29 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20180426121432-d811d2e9bf89/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20180408092902-8b1c2da0d56d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rubenv/sql-migrate v0.0.0-20181106121204-ba2c6a7295c5 h1:4fmVndFuOuFREP0MPVT+bymEYx/mvRBnmGamM1YfH8c=
|
||||
github.com/rubenv/sql-migrate v0.0.0-20181106121204-ba2c6a7295c5/go.mod h1:WS0rl9eEliYI8DPnr3TOwz4439pay+qNgzJoVya/DmY=
|
||||
github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/sirupsen/logrus v1.2.0 h1:juTguoYk5qI21pwyTXY3B3Y5cOTH3ZUyZCg1v/mihuo=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sony/gobreaker v0.0.0-20180905101324-b2a34562d02c h1:7EMc5KMRVlkzEyK5n4YqdPEsmO+6AlAGCJiqnqW6n2Y=
|
||||
github.com/sony/gobreaker v0.0.0-20180905101324-b2a34562d02c/go.mod h1:XvpJiTD8NibaH7z0NzyfhR1+NQDtR9F/x92xheTwC9k=
|
||||
@ -221,20 +260,21 @@ github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.5.0 h1:GpsTwfsQ27oS/Aha/6d1oD7tpKIqWnOA6tgOX9HHkt4=
|
||||
github.com/spf13/viper v1.5.0/go.mod h1:AkYRkVJF8TkSG/xet6PzXX+l39KhhXa2pdqVSxnTcn4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
@ -244,89 +284,122 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/uber/jaeger-client-go v2.16.0+incompatible h1:Q2Pp6v3QYiocMxomCaJuwQGFt7E53bPYqEgug/AoBtY=
|
||||
github.com/uber/jaeger-client-go v2.16.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-client-go v2.22.1+incompatible h1:NHcubEkVbahf9t3p75TOCR83gdUHXjRJvjoBh1yACsM=
|
||||
github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
|
||||
github.com/uber/jaeger-lib v2.0.0+incompatible h1:iMSCV0rmXEogjNWPh2D0xk9YVKvrtGoHJNe9ebLu/pw=
|
||||
github.com/uber/jaeger-lib v2.0.0+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
|
||||
github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||
github.com/ugorji/go v1.1.4 h1:j4s+tAvLfL3bZyefP2SEWmhBzmuIlH/eqNuPdFPgngw=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/x448/senml v0.2.0 h1:W6P7p4bA8ZvsEkl6+f7kjoc9n5vPHBYL5V6kGJkyDy4=
|
||||
github.com/x448/senml v0.2.0/go.mod h1:dAsCrOGmYEKO/L/DUpZpinKEgI1PCxAUjt2eAwXCDx8=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
|
||||
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
|
||||
github.com/xdg/stringprep v1.0.1-0.20180714160509-73f8eece6fdc h1:vIp1tjhVogU0yBy7w96P027ewvNPeH6gzuNcoc+NReU=
|
||||
github.com/xdg/stringprep v1.0.1-0.20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.mongodb.org/mongo-driver v1.0.0 h1:KxPRDyfB2xXnDE2My8acoOWBQkfv3tz0SaWTRZjJR0c=
|
||||
go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.mongodb.org/mongo-driver v1.1.3 h1:++7u8r9adKhGR+I79NfEtYrk2ktjenErXM99PSufIoI=
|
||||
go.mongodb.org/mongo-driver v1.1.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2 h1:y102fOLFqhV41b+4GPiJoa0k/x+pJcEi2/HB1Y5T6fU=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180509002218-f73e4c9ed3b7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180510032850-7dfd1290c791/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed h1:uPxWBzB3+mlnjy9W58qY1j/cjyFjutgw/Vhan2zLy/A=
|
||||
golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.0.0-20190808205415-ced62fe5104b h1:wlZ2AJblZitrh7dfm5OX2WenXLBZCuWqUeNczop2lPA=
|
||||
gonum.org/v1/gonum v0.0.0-20190808205415-ced62fe5104b/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc=
|
||||
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180427144745-86e600f69ee4/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200225123651-fc8f55426688 h1:1+0Z5cgv1eDXJD9z2tdQF9PSSQnJXwism490hJydMRI=
|
||||
google.golang.org/genproto v0.0.0-20200225123651-fc8f55426688/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/gorp.v1 v1.7.1 h1:GBB9KrWRATQZh95HJyVGUZrWwOPswitEYEyqlK8JbAA=
|
||||
@ -335,6 +408,8 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ory-am/dockertest.v3 v3.3.2 h1:NgIHJacfXajJResc7luKYPF/F2kul6MXqbleEjv4PAY=
|
||||
gopkg.in/ory-am/dockertest.v3 v3.3.2/go.mod h1:s9mmoLkaGeAh97qygnNj4xWkiN7e1SKekYC6CovU+ek=
|
||||
gopkg.in/ory/dockertest.v3 v3.3.5 h1:bm2RXztqdTSinb1tUP9/iFTPmhy3sk2EL2k9GSMKNEE=
|
||||
gopkg.in/ory/dockertest.v3 v3.3.5/go.mod h1:wI78nwA6jQZVXv3va0CcbJAuftRnAa063zO5Fek7+uI=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
@ -344,6 +419,8 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/mainflux/mainflux"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const prefix = "channel"
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/mainflux/mainflux"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
var _ mainflux.MessagePublisher = (*natsPublisher)(nil)
|
||||
|
206
mqtt/mproxy/mproxy.go
Normal file
206
mqtt/mproxy/mproxy.go
Normal file
@ -0,0 +1,206 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package mproxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/mqtt/mproxy/redis"
|
||||
"github.com/mainflux/mproxy/pkg/events"
|
||||
opentracing "github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
var (
|
||||
_ events.Event = (*Event)(nil)
|
||||
channelRegExp = regexp.MustCompile(`^\/?channels\/([\w\-]+)\/messages(\/[^?]*)?(\?.*)?$`)
|
||||
ctRegExp = regexp.MustCompile(`^(\/.*)?\/ct\/([^\/]+)$`)
|
||||
errMalformedTopic = errors.New("malformed topic")
|
||||
errMalformedData = errors.New("malformed request data")
|
||||
errMalformedSubtopic = errors.New("malformed subtopic")
|
||||
)
|
||||
|
||||
// Event implements events.Event interface
|
||||
type Event struct {
|
||||
tc mainflux.ThingsServiceClient
|
||||
mp mainflux.MessagePublisher
|
||||
tracer opentracing.Tracer
|
||||
logger logger.Logger
|
||||
es redis.EventStore
|
||||
}
|
||||
|
||||
// New creates new Event entity
|
||||
func New(tc mainflux.ThingsServiceClient, mp mainflux.MessagePublisher, es redis.EventStore,
|
||||
logger logger.Logger, tracer opentracing.Tracer) *Event {
|
||||
return &Event{
|
||||
tc: tc,
|
||||
mp: mp,
|
||||
es: es,
|
||||
tracer: tracer,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// AuthRegister is called on device connection,
|
||||
// prior forwarding to the MQTT broker
|
||||
func (e *Event) AuthRegister(username, clientID *string, password *[]byte) error {
|
||||
e.logger.Info(fmt.Sprintf("AuthRegister() - clientID: %s, username: %s",
|
||||
*clientID, *username))
|
||||
|
||||
t := &mainflux.Token{
|
||||
Value: string(*password),
|
||||
}
|
||||
|
||||
thid, err := e.tc.Identify(context.TODO(), t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if thid.Value != *username {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Event) authAccess(username string, topic string) error {
|
||||
// Topics are in the format:
|
||||
// channels/<channel_id>/messages/<subtopic>/.../ct/<content_type>
|
||||
if !channelRegExp.Match([]byte(topic)) {
|
||||
e.logger.Info(fmt.Sprintf("Malformed topic %s", topic))
|
||||
return errMalformedTopic
|
||||
}
|
||||
|
||||
channelParts := channelRegExp.FindStringSubmatch(topic)
|
||||
if len(channelParts) < 1 {
|
||||
return errMalformedData
|
||||
}
|
||||
|
||||
chanID := channelParts[1]
|
||||
|
||||
ar := &mainflux.AccessByIDReq{
|
||||
ThingID: username,
|
||||
ChanID: chanID,
|
||||
}
|
||||
_, err := e.tc.CanAccessByID(context.TODO(), ar)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AuthPublish is called on device publish,
|
||||
// prior forwarding to the MQTT broker
|
||||
func (e *Event) AuthPublish(username, clientID string, topic *string, payload *[]byte) error {
|
||||
e.logger.Info(fmt.Sprintf("AuthPublish() - clientID: %s, topic: %s", clientID, *topic))
|
||||
return e.authAccess(username, *topic)
|
||||
}
|
||||
|
||||
// AuthSubscribe is called on device publish,
|
||||
// prior forwarding to the MQTT broker
|
||||
func (e *Event) AuthSubscribe(username, clientID string, topics *[]string) error {
|
||||
e.logger.Info(fmt.Sprintf("AuthSubscribe() - clientID: %s, topics: %s", clientID, strings.Join(*topics, ",")))
|
||||
|
||||
for _, v := range *topics {
|
||||
if err := e.authAccess(username, v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Register - after client sucesfully connected
|
||||
func (e *Event) Register(clientID string) {
|
||||
e.logger.Info(fmt.Sprintf("Register() - clientID: %s", clientID))
|
||||
}
|
||||
|
||||
func parseSubtopic(subtopic string) (string, error) {
|
||||
if subtopic == "" {
|
||||
return subtopic, nil
|
||||
}
|
||||
|
||||
subtopic, err := url.QueryUnescape(subtopic)
|
||||
if err != nil {
|
||||
return "", errMalformedSubtopic
|
||||
}
|
||||
subtopic = strings.Replace(subtopic, "/", ".", -1)
|
||||
|
||||
elems := strings.Split(subtopic, ".")
|
||||
filteredElems := []string{}
|
||||
for _, elem := range elems {
|
||||
if elem == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(elem) > 1 && (strings.Contains(elem, "*") || strings.Contains(elem, ">")) {
|
||||
return "", errMalformedSubtopic
|
||||
}
|
||||
|
||||
filteredElems = append(filteredElems, elem)
|
||||
}
|
||||
|
||||
subtopic = strings.Join(filteredElems, ".")
|
||||
return subtopic, nil
|
||||
}
|
||||
|
||||
// Publish - after client sucesfully published
|
||||
func (e *Event) Publish(clientID, topic string, payload []byte) {
|
||||
e.logger.Info(fmt.Sprintf("Publish() - clientID: %s, topic: %s", clientID, topic))
|
||||
// Topics are in the format:
|
||||
// channels/<channel_id>/messages/<subtopic>/.../ct/<content_type>
|
||||
|
||||
channelParts := channelRegExp.FindStringSubmatch(topic)
|
||||
if len(channelParts) < 1 {
|
||||
e.logger.Info(fmt.Sprintf("Error in mqtt publish %s", errMalformedData))
|
||||
return
|
||||
}
|
||||
|
||||
chanID := channelParts[1]
|
||||
subtopic := channelParts[2]
|
||||
|
||||
ct := ""
|
||||
if stParts := ctRegExp.FindStringSubmatch(subtopic); len(stParts) > 1 {
|
||||
ct = stParts[2]
|
||||
subtopic = stParts[1]
|
||||
}
|
||||
|
||||
subtopic, err := parseSubtopic(subtopic)
|
||||
if err != nil {
|
||||
e.logger.Info(fmt.Sprintf("Error in mqtt publish %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
msg := mainflux.Message{
|
||||
Protocol: "mqtt",
|
||||
ContentType: ct,
|
||||
Channel: chanID,
|
||||
Subtopic: subtopic,
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
if err := e.mp.Publish(context.TODO(), "", msg); err != nil {
|
||||
e.logger.Info(fmt.Sprintf("Error in mqtt publish %s", err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe - after client sucesfully subscribed
|
||||
func (e *Event) Subscribe(clientID string, topics []string) {
|
||||
e.logger.Info(fmt.Sprintf("Subscribe() - clientID: %s, topics: %s", clientID, strings.Join(topics, ",")))
|
||||
}
|
||||
|
||||
// Unubscribe - after client unsubscribed
|
||||
func (e *Event) Unsubscribe(clientID string, topics []string) {
|
||||
|
||||
e.logger.Info(fmt.Sprintf("Unubscribe() - clientID: %s, topics: %s", clientID, strings.Join(topics, ",")))
|
||||
}
|
5
mqtt/mproxy/nats/doc.go
Normal file
5
mqtt/mproxy/nats/doc.go
Normal file
@ -0,0 +1,5 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package nats contains NATS message publisher implementation.
|
||||
package nats
|
39
mqtt/mproxy/nats/publisher.go
Normal file
39
mqtt/mproxy/nats/publisher.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package nats
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/mainflux/mainflux"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const prefix = "channel"
|
||||
|
||||
var _ mainflux.MessagePublisher = (*natsPublisher)(nil)
|
||||
|
||||
type natsPublisher struct {
|
||||
nc *broker.Conn
|
||||
}
|
||||
|
||||
// NewMessagePublisher instantiates NATS message publisher.
|
||||
func NewMessagePublisher(nc *broker.Conn) mainflux.MessagePublisher {
|
||||
return &natsPublisher{nc: nc}
|
||||
}
|
||||
|
||||
func (pub *natsPublisher) Publish(_ context.Context, _ string, msg mainflux.Message) error {
|
||||
data, err := proto.Marshal(&msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
subject := fmt.Sprintf("%s.%s", prefix, msg.Channel)
|
||||
if msg.Subtopic != "" {
|
||||
subject = fmt.Sprintf("%s.%s", subject, msg.Subtopic)
|
||||
}
|
||||
return pub.nc.Publish(subject, data)
|
||||
}
|
6
mqtt/mproxy/redis/doc.go
Normal file
6
mqtt/mproxy/redis/doc.go
Normal file
@ -0,0 +1,6 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package redis contains cache implementations using Redis as
|
||||
// the underlying database.
|
||||
package redis
|
28
mqtt/mproxy/redis/events.go
Normal file
28
mqtt/mproxy/redis/events.go
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package redis
|
||||
|
||||
type event interface {
|
||||
Encode() map[string]interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
_ event = (*mqttEvent)(nil)
|
||||
)
|
||||
|
||||
type mqttEvent struct {
|
||||
clientID string
|
||||
timestamp string
|
||||
eventType string
|
||||
instance string
|
||||
}
|
||||
|
||||
func (me mqttEvent) Encode() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"thing_id": me.clientID,
|
||||
"timestamp": me.timestamp,
|
||||
"event_type": me.eventType,
|
||||
"instance": me.instance,
|
||||
}
|
||||
}
|
65
mqtt/mproxy/redis/streams.go
Normal file
65
mqtt/mproxy/redis/streams.go
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) Mainflux
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package redis
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
)
|
||||
|
||||
const (
|
||||
streamID = "mainflux.mqtt"
|
||||
streamLen = 1000
|
||||
)
|
||||
|
||||
// EventStore is a struct used to store event streams in Redis
|
||||
type EventStore struct {
|
||||
client *redis.Client
|
||||
instance string
|
||||
}
|
||||
|
||||
// NewEventStore returns wrapper around mProxy service that sends
|
||||
// events to event store.
|
||||
func NewEventStore(client *redis.Client, instance string) EventStore {
|
||||
return EventStore{
|
||||
client: client,
|
||||
instance: instance,
|
||||
}
|
||||
}
|
||||
|
||||
func (es EventStore) storeEvent(clientID, eventType string) error {
|
||||
|
||||
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||
|
||||
event := mqttEvent{
|
||||
clientID: clientID,
|
||||
timestamp: timestamp,
|
||||
eventType: eventType,
|
||||
instance: es.instance,
|
||||
}
|
||||
|
||||
record := &redis.XAddArgs{
|
||||
Stream: streamID,
|
||||
MaxLenApprox: streamLen,
|
||||
Values: event.Encode(),
|
||||
}
|
||||
|
||||
if err := es.client.XAdd(record).Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Connect issues event on MQTT CONNECT
|
||||
func (es EventStore) Connect(clientID string) error {
|
||||
return es.storeEvent(clientID, "connect")
|
||||
}
|
||||
|
||||
// Disconnect issues event on MQTT CONNECT
|
||||
func (es EventStore) Disconnect(clientID string) error {
|
||||
return es.storeEvent(clientID, "disconnect")
|
||||
}
|
@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/mainflux/mainflux"
|
||||
broker "github.com/nats-io/go-nats"
|
||||
broker "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
var _ mainflux.MessagePublisher = (*natsPublisher)(nil)
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"github.com/gocql/gocql"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/writers/cassandra"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
var logger, _ = log.New(os.Stdout, log.Info.String())
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
influxdb "github.com/influxdata/influxdb/client/v2"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/readers/postgres"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -1,10 +1,10 @@
|
||||
# This script contains commands to be executed by the CI tool.
|
||||
NPROC=$(nproc)
|
||||
GO_VERSION=1.13
|
||||
PROTOC_VERSION=3.11.1
|
||||
PROTOC_GEN_VERSION=v1.3.2
|
||||
PROTOC_VERSION=3.11.4
|
||||
PROTOC_GEN_VERSION=v1.3.3
|
||||
PROTOC_GOFAST_VERSION=v1.3.1
|
||||
GRPC_VERSION=v1.24.0
|
||||
GRPC_VERSION=v1.27.1
|
||||
|
||||
function version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
|
||||
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/things/postgres"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-redis/redis"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/mainflux/mainflux"
|
||||
"github.com/nats-io/go-nats"
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"github.com/mainflux/mainflux"
|
||||
log "github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mainflux/twins"
|
||||
"github.com/nats-io/go-nats"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/mainflux/mainflux/users/postgres"
|
||||
dockertest "gopkg.in/ory-am/dockertest.v3"
|
||||
dockertest "gopkg.in/ory/dockertest.v3"
|
||||
)
|
||||
|
||||
const wrong string = "wrong-value"
|
||||
|
2
vendor/github.com/golang/protobuf/proto/lib.go
generated
vendored
2
vendor/github.com/golang/protobuf/proto/lib.go
generated
vendored
@ -393,7 +393,7 @@ func (p *Buffer) Bytes() []byte { return p.buf }
|
||||
// than relying on this API.
|
||||
//
|
||||
// If deterministic serialization is requested, map entries will be sorted
|
||||
// by keys in lexographical order. This is an implementation detail and
|
||||
// by keys in lexicographical order. This is an implementation detail and
|
||||
// subject to change.
|
||||
func (p *Buffer) SetDeterministic(deterministic bool) {
|
||||
p.deterministic = deterministic
|
||||
|
6
vendor/github.com/golang/protobuf/proto/text.go
generated
vendored
6
vendor/github.com/golang/protobuf/proto/text.go
generated
vendored
@ -456,6 +456,8 @@ func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
|
||||
// writeAny writes an arbitrary field.
|
||||
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||
v = reflect.Indirect(v)
|
||||
@ -519,8 +521,8 @@ func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Propert
|
||||
// mutating this value.
|
||||
v = v.Addr()
|
||||
}
|
||||
if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||
text, err := etm.MarshalText()
|
||||
if v.Type().Implements(textMarshalerType) {
|
||||
text, err := v.Interface().(encoding.TextMarshaler).MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
9
vendor/github.com/google/uuid/.travis.yml
generated
vendored
Normal file
9
vendor/github.com/google/uuid/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.4.3
|
||||
- 1.5.3
|
||||
- tip
|
||||
|
||||
script:
|
||||
- go test -v ./...
|
10
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
Normal file
10
vendor/github.com/google/uuid/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
# How to contribute
|
||||
|
||||
We definitely welcome patches and contribution to this project!
|
||||
|
||||
### Legal requirements
|
||||
|
||||
In order to protect both you and ourselves, you will need to sign the
|
||||
[Contributor License Agreement](https://cla.developers.google.com/clas).
|
||||
|
||||
You may have already signed it for other Google projects.
|
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
Normal file
9
vendor/github.com/google/uuid/CONTRIBUTORS
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
Paul Borman <borman@google.com>
|
||||
bmatsuo
|
||||
shawnps
|
||||
theory
|
||||
jboverfelt
|
||||
dsymonds
|
||||
cd1
|
||||
wallclockbuilder
|
||||
dansouza
|
27
vendor/github.com/google/uuid/LICENSE
generated
vendored
Normal file
27
vendor/github.com/google/uuid/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009,2014 Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
19
vendor/github.com/google/uuid/README.md
generated
vendored
Normal file
19
vendor/github.com/google/uuid/README.md
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# uuid 
|
||||
The uuid package generates and inspects UUIDs based on
|
||||
[RFC 4122](http://tools.ietf.org/html/rfc4122)
|
||||
and DCE 1.1: Authentication and Security Services.
|
||||
|
||||
This package is based on the github.com/pborman/uuid package (previously named
|
||||
code.google.com/p/go-uuid). It differs from these earlier packages in that
|
||||
a UUID is a 16 byte array rather than a byte slice. One loss due to this
|
||||
change is the ability to represent an invalid UUID (vs a NIL UUID).
|
||||
|
||||
###### Install
|
||||
`go get github.com/google/uuid`
|
||||
|
||||
###### Documentation
|
||||
[](http://godoc.org/github.com/google/uuid)
|
||||
|
||||
Full `go doc` style documentation for the package can be viewed online without
|
||||
installing this package by using the GoDoc site here:
|
||||
http://godoc.org/github.com/google/uuid
|
80
vendor/github.com/google/uuid/dce.go
generated
vendored
Normal file
80
vendor/github.com/google/uuid/dce.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// A Domain represents a Version 2 domain
|
||||
type Domain byte
|
||||
|
||||
// Domain constants for DCE Security (Version 2) UUIDs.
|
||||
const (
|
||||
Person = Domain(0)
|
||||
Group = Domain(1)
|
||||
Org = Domain(2)
|
||||
)
|
||||
|
||||
// NewDCESecurity returns a DCE Security (Version 2) UUID.
|
||||
//
|
||||
// The domain should be one of Person, Group or Org.
|
||||
// On a POSIX system the id should be the users UID for the Person
|
||||
// domain and the users GID for the Group. The meaning of id for
|
||||
// the domain Org or on non-POSIX systems is site defined.
|
||||
//
|
||||
// For a given domain/id pair the same token may be returned for up to
|
||||
// 7 minutes and 10 seconds.
|
||||
func NewDCESecurity(domain Domain, id uint32) (UUID, error) {
|
||||
uuid, err := NewUUID()
|
||||
if err == nil {
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x20 // Version 2
|
||||
uuid[9] = byte(domain)
|
||||
binary.BigEndian.PutUint32(uuid[0:], id)
|
||||
}
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
// NewDCEPerson returns a DCE Security (Version 2) UUID in the person
|
||||
// domain with the id returned by os.Getuid.
|
||||
//
|
||||
// NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
func NewDCEPerson() (UUID, error) {
|
||||
return NewDCESecurity(Person, uint32(os.Getuid()))
|
||||
}
|
||||
|
||||
// NewDCEGroup returns a DCE Security (Version 2) UUID in the group
|
||||
// domain with the id returned by os.Getgid.
|
||||
//
|
||||
// NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
func NewDCEGroup() (UUID, error) {
|
||||
return NewDCESecurity(Group, uint32(os.Getgid()))
|
||||
}
|
||||
|
||||
// Domain returns the domain for a Version 2 UUID. Domains are only defined
|
||||
// for Version 2 UUIDs.
|
||||
func (uuid UUID) Domain() Domain {
|
||||
return Domain(uuid[9])
|
||||
}
|
||||
|
||||
// ID returns the id for a Version 2 UUID. IDs are only defined for Version 2
|
||||
// UUIDs.
|
||||
func (uuid UUID) ID() uint32 {
|
||||
return binary.BigEndian.Uint32(uuid[0:4])
|
||||
}
|
||||
|
||||
func (d Domain) String() string {
|
||||
switch d {
|
||||
case Person:
|
||||
return "Person"
|
||||
case Group:
|
||||
return "Group"
|
||||
case Org:
|
||||
return "Org"
|
||||
}
|
||||
return fmt.Sprintf("Domain%d", int(d))
|
||||
}
|
12
vendor/github.com/google/uuid/doc.go
generated
vendored
Normal file
12
vendor/github.com/google/uuid/doc.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package uuid generates and inspects UUIDs.
|
||||
//
|
||||
// UUIDs are based on RFC 4122 and DCE 1.1: Authentication and Security
|
||||
// Services.
|
||||
//
|
||||
// A UUID is a 16 byte (128 bit) array. UUIDs may be used as keys to
|
||||
// maps or compared directly.
|
||||
package uuid
|
1
vendor/github.com/google/uuid/go.mod
generated
vendored
Normal file
1
vendor/github.com/google/uuid/go.mod
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
module github.com/google/uuid
|
53
vendor/github.com/google/uuid/hash.go
generated
vendored
Normal file
53
vendor/github.com/google/uuid/hash.go
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
)
|
||||
|
||||
// Well known namespace IDs and UUIDs
|
||||
var (
|
||||
NameSpaceDNS = Must(Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceURL = Must(Parse("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceOID = Must(Parse("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
|
||||
NameSpaceX500 = Must(Parse("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
|
||||
Nil UUID // empty UUID, all zeros
|
||||
)
|
||||
|
||||
// NewHash returns a new UUID derived from the hash of space concatenated with
|
||||
// data generated by h. The hash should be at least 16 byte in length. The
|
||||
// first 16 bytes of the hash are used to form the UUID. The version of the
|
||||
// UUID will be the lower 4 bits of version. NewHash is used to implement
|
||||
// NewMD5 and NewSHA1.
|
||||
func NewHash(h hash.Hash, space UUID, data []byte, version int) UUID {
|
||||
h.Reset()
|
||||
h.Write(space[:])
|
||||
h.Write(data)
|
||||
s := h.Sum(nil)
|
||||
var uuid UUID
|
||||
copy(uuid[:], s)
|
||||
uuid[6] = (uuid[6] & 0x0f) | uint8((version&0xf)<<4)
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||
return uuid
|
||||
}
|
||||
|
||||
// NewMD5 returns a new MD5 (Version 3) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(md5.New(), space, data, 3)
|
||||
func NewMD5(space UUID, data []byte) UUID {
|
||||
return NewHash(md5.New(), space, data, 3)
|
||||
}
|
||||
|
||||
// NewSHA1 returns a new SHA1 (Version 5) UUID based on the
|
||||
// supplied name space and data. It is the same as calling:
|
||||
//
|
||||
// NewHash(sha1.New(), space, data, 5)
|
||||
func NewSHA1(space UUID, data []byte) UUID {
|
||||
return NewHash(sha1.New(), space, data, 5)
|
||||
}
|
37
vendor/github.com/google/uuid/marshal.go
generated
vendored
Normal file
37
vendor/github.com/google/uuid/marshal.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "fmt"
|
||||
|
||||
// MarshalText implements encoding.TextMarshaler.
|
||||
func (uuid UUID) MarshalText() ([]byte, error) {
|
||||
var js [36]byte
|
||||
encodeHex(js[:], uuid)
|
||||
return js[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (uuid *UUID) UnmarshalText(data []byte) error {
|
||||
id, err := ParseBytes(data)
|
||||
if err == nil {
|
||||
*uuid = id
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalBinary implements encoding.BinaryMarshaler.
|
||||
func (uuid UUID) MarshalBinary() ([]byte, error) {
|
||||
return uuid[:], nil
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements encoding.BinaryUnmarshaler.
|
||||
func (uuid *UUID) UnmarshalBinary(data []byte) error {
|
||||
if len(data) != 16 {
|
||||
return fmt.Errorf("invalid UUID (got %d bytes)", len(data))
|
||||
}
|
||||
copy(uuid[:], data)
|
||||
return nil
|
||||
}
|
90
vendor/github.com/google/uuid/node.go
generated
vendored
Normal file
90
vendor/github.com/google/uuid/node.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
nodeMu sync.Mutex
|
||||
ifname string // name of interface being used
|
||||
nodeID [6]byte // hardware for version 1 UUIDs
|
||||
zeroID [6]byte // nodeID with only 0's
|
||||
)
|
||||
|
||||
// NodeInterface returns the name of the interface from which the NodeID was
|
||||
// derived. The interface "user" is returned if the NodeID was set by
|
||||
// SetNodeID.
|
||||
func NodeInterface() string {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
return ifname
|
||||
}
|
||||
|
||||
// SetNodeInterface selects the hardware address to be used for Version 1 UUIDs.
|
||||
// If name is "" then the first usable interface found will be used or a random
|
||||
// Node ID will be generated. If a named interface cannot be found then false
|
||||
// is returned.
|
||||
//
|
||||
// SetNodeInterface never fails when name is "".
|
||||
func SetNodeInterface(name string) bool {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
return setNodeInterface(name)
|
||||
}
|
||||
|
||||
func setNodeInterface(name string) bool {
|
||||
iname, addr := getHardwareInterface(name) // null implementation for js
|
||||
if iname != "" && addr != nil {
|
||||
ifname = iname
|
||||
copy(nodeID[:], addr)
|
||||
return true
|
||||
}
|
||||
|
||||
// We found no interfaces with a valid hardware address. If name
|
||||
// does not specify a specific interface generate a random Node ID
|
||||
// (section 4.1.6)
|
||||
if name == "" {
|
||||
ifname = "random"
|
||||
randomBits(nodeID[:])
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NodeID returns a slice of a copy of the current Node ID, setting the Node ID
|
||||
// if not already set.
|
||||
func NodeID() []byte {
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
nid := nodeID
|
||||
return nid[:]
|
||||
}
|
||||
|
||||
// SetNodeID sets the Node ID to be used for Version 1 UUIDs. The first 6 bytes
|
||||
// of id are used. If id is less than 6 bytes then false is returned and the
|
||||
// Node ID is not set.
|
||||
func SetNodeID(id []byte) bool {
|
||||
if len(id) < 6 {
|
||||
return false
|
||||
}
|
||||
defer nodeMu.Unlock()
|
||||
nodeMu.Lock()
|
||||
copy(nodeID[:], id)
|
||||
ifname = "user"
|
||||
return true
|
||||
}
|
||||
|
||||
// NodeID returns the 6 byte node id encoded in uuid. It returns nil if uuid is
|
||||
// not valid. The NodeID is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) NodeID() []byte {
|
||||
var node [6]byte
|
||||
copy(node[:], uuid[10:])
|
||||
return node[:]
|
||||
}
|
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
Normal file
12
vendor/github.com/google/uuid/node_js.go
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build js
|
||||
|
||||
package uuid
|
||||
|
||||
// getHardwareInterface returns nil values for the JS version of the code.
|
||||
// This remvoves the "net" dependency, because it is not used in the browser.
|
||||
// Using the "net" library inflates the size of the transpiled JS code by 673k bytes.
|
||||
func getHardwareInterface(name string) (string, []byte) { return "", nil }
|
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
Normal file
33
vendor/github.com/google/uuid/node_net.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2017 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !js
|
||||
|
||||
package uuid
|
||||
|
||||
import "net"
|
||||
|
||||
var interfaces []net.Interface // cached list of interfaces
|
||||
|
||||
// getHardwareInterface returns the name and hardware address of interface name.
|
||||
// If name is "" then the name and hardware address of one of the system's
|
||||
// interfaces is returned. If no interfaces are found (name does not exist or
|
||||
// there are no interfaces) then "", nil is returned.
|
||||
//
|
||||
// Only addresses of at least 6 bytes are returned.
|
||||
func getHardwareInterface(name string) (string, []byte) {
|
||||
if interfaces == nil {
|
||||
var err error
|
||||
interfaces, err = net.Interfaces()
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
}
|
||||
for _, ifs := range interfaces {
|
||||
if len(ifs.HardwareAddr) >= 6 && (name == "" || name == ifs.Name) {
|
||||
return ifs.Name, ifs.HardwareAddr
|
||||
}
|
||||
}
|
||||
return "", nil
|
||||
}
|
59
vendor/github.com/google/uuid/sql.go
generated
vendored
Normal file
59
vendor/github.com/google/uuid/sql.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Scan implements sql.Scanner so UUIDs can be read from databases transparently
|
||||
// Currently, database types that map to string and []byte are supported. Please
|
||||
// consult database-specific driver documentation for matching types.
|
||||
func (uuid *UUID) Scan(src interface{}) error {
|
||||
switch src := src.(type) {
|
||||
case nil:
|
||||
return nil
|
||||
|
||||
case string:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if src == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// see Parse for required string format
|
||||
u, err := Parse(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Scan: %v", err)
|
||||
}
|
||||
|
||||
*uuid = u
|
||||
|
||||
case []byte:
|
||||
// if an empty UUID comes from a table, we return a null UUID
|
||||
if len(src) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// assumes a simple slice of bytes if 16 bytes
|
||||
// otherwise attempts to parse
|
||||
if len(src) != 16 {
|
||||
return uuid.Scan(string(src))
|
||||
}
|
||||
copy((*uuid)[:], src)
|
||||
|
||||
default:
|
||||
return fmt.Errorf("Scan: unable to scan type %T into UUID", src)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements sql.Valuer so that UUIDs can be written to databases
|
||||
// transparently. Currently, UUIDs map to strings. Please consult
|
||||
// database-specific driver documentation for matching types.
|
||||
func (uuid UUID) Value() (driver.Value, error) {
|
||||
return uuid.String(), nil
|
||||
}
|
123
vendor/github.com/google/uuid/time.go
generated
vendored
Normal file
123
vendor/github.com/google/uuid/time.go
generated
vendored
Normal file
@ -0,0 +1,123 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Time represents a time as the number of 100's of nanoseconds since 15 Oct
|
||||
// 1582.
|
||||
type Time int64
|
||||
|
||||
const (
|
||||
lillian = 2299160 // Julian day of 15 Oct 1582
|
||||
unix = 2440587 // Julian day of 1 Jan 1970
|
||||
epoch = unix - lillian // Days between epochs
|
||||
g1582 = epoch * 86400 // seconds between epochs
|
||||
g1582ns100 = g1582 * 10000000 // 100s of a nanoseconds between epochs
|
||||
)
|
||||
|
||||
var (
|
||||
timeMu sync.Mutex
|
||||
lasttime uint64 // last time we returned
|
||||
clockSeq uint16 // clock sequence for this run
|
||||
|
||||
timeNow = time.Now // for testing
|
||||
)
|
||||
|
||||
// UnixTime converts t the number of seconds and nanoseconds using the Unix
|
||||
// epoch of 1 Jan 1970.
|
||||
func (t Time) UnixTime() (sec, nsec int64) {
|
||||
sec = int64(t - g1582ns100)
|
||||
nsec = (sec % 10000000) * 100
|
||||
sec /= 10000000
|
||||
return sec, nsec
|
||||
}
|
||||
|
||||
// GetTime returns the current Time (100s of nanoseconds since 15 Oct 1582) and
|
||||
// clock sequence as well as adjusting the clock sequence as needed. An error
|
||||
// is returned if the current time cannot be determined.
|
||||
func GetTime() (Time, uint16, error) {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
return getTime()
|
||||
}
|
||||
|
||||
func getTime() (Time, uint16, error) {
|
||||
t := timeNow()
|
||||
|
||||
// If we don't have a clock sequence already, set one.
|
||||
if clockSeq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
now := uint64(t.UnixNano()/100) + g1582ns100
|
||||
|
||||
// If time has gone backwards with this clock sequence then we
|
||||
// increment the clock sequence
|
||||
if now <= lasttime {
|
||||
clockSeq = ((clockSeq + 1) & 0x3fff) | 0x8000
|
||||
}
|
||||
lasttime = now
|
||||
return Time(now), clockSeq, nil
|
||||
}
|
||||
|
||||
// ClockSequence returns the current clock sequence, generating one if not
|
||||
// already set. The clock sequence is only used for Version 1 UUIDs.
|
||||
//
|
||||
// The uuid package does not use global static storage for the clock sequence or
|
||||
// the last time a UUID was generated. Unless SetClockSequence is used, a new
|
||||
// random clock sequence is generated the first time a clock sequence is
|
||||
// requested by ClockSequence, GetTime, or NewUUID. (section 4.2.1.1)
|
||||
func ClockSequence() int {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
return clockSequence()
|
||||
}
|
||||
|
||||
func clockSequence() int {
|
||||
if clockSeq == 0 {
|
||||
setClockSequence(-1)
|
||||
}
|
||||
return int(clockSeq & 0x3fff)
|
||||
}
|
||||
|
||||
// SetClockSequence sets the clock sequence to the lower 14 bits of seq. Setting to
|
||||
// -1 causes a new sequence to be generated.
|
||||
func SetClockSequence(seq int) {
|
||||
defer timeMu.Unlock()
|
||||
timeMu.Lock()
|
||||
setClockSequence(seq)
|
||||
}
|
||||
|
||||
func setClockSequence(seq int) {
|
||||
if seq == -1 {
|
||||
var b [2]byte
|
||||
randomBits(b[:]) // clock sequence
|
||||
seq = int(b[0])<<8 | int(b[1])
|
||||
}
|
||||
oldSeq := clockSeq
|
||||
clockSeq = uint16(seq&0x3fff) | 0x8000 // Set our variant
|
||||
if oldSeq != clockSeq {
|
||||
lasttime = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Time returns the time in 100s of nanoseconds since 15 Oct 1582 encoded in
|
||||
// uuid. The time is only defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) Time() Time {
|
||||
time := int64(binary.BigEndian.Uint32(uuid[0:4]))
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[4:6])) << 32
|
||||
time |= int64(binary.BigEndian.Uint16(uuid[6:8])&0xfff) << 48
|
||||
return Time(time)
|
||||
}
|
||||
|
||||
// ClockSequence returns the clock sequence encoded in uuid.
|
||||
// The clock sequence is only well defined for version 1 and 2 UUIDs.
|
||||
func (uuid UUID) ClockSequence() int {
|
||||
return int(binary.BigEndian.Uint16(uuid[8:10])) & 0x3fff
|
||||
}
|
43
vendor/github.com/google/uuid/util.go
generated
vendored
Normal file
43
vendor/github.com/google/uuid/util.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// randomBits completely fills slice b with random data.
|
||||
func randomBits(b []byte) {
|
||||
if _, err := io.ReadFull(rander, b); err != nil {
|
||||
panic(err.Error()) // rand should never fail
|
||||
}
|
||||
}
|
||||
|
||||
// xvalues returns the value of a byte as a hexadecimal digit or 255.
|
||||
var xvalues = [256]byte{
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||
}
|
||||
|
||||
// xtob converts hex characters x1 and x2 into a byte.
|
||||
func xtob(x1, x2 byte) (byte, bool) {
|
||||
b1 := xvalues[x1]
|
||||
b2 := xvalues[x2]
|
||||
return (b1 << 4) | b2, b1 != 255 && b2 != 255
|
||||
}
|
245
vendor/github.com/google/uuid/uuid.go
generated
vendored
Normal file
245
vendor/github.com/google/uuid/uuid.go
generated
vendored
Normal file
@ -0,0 +1,245 @@
|
||||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A UUID is a 128 bit (16 byte) Universal Unique IDentifier as defined in RFC
|
||||
// 4122.
|
||||
type UUID [16]byte
|
||||
|
||||
// A Version represents a UUID's version.
|
||||
type Version byte
|
||||
|
||||
// A Variant represents a UUID's variant.
|
||||
type Variant byte
|
||||
|
||||
// Constants returned by Variant.
|
||||
const (
|
||||
Invalid = Variant(iota) // Invalid UUID
|
||||
RFC4122 // The variant specified in RFC4122
|
||||
Reserved // Reserved, NCS backward compatibility.
|
||||
Microsoft // Reserved, Microsoft Corporation backward compatibility.
|
||||
Future // Reserved for future definition.
|
||||
)
|
||||
|
||||
var rander = rand.Reader // random function
|
||||
|
||||
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
||||
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
|
||||
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
|
||||
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
|
||||
func Parse(s string) (UUID, error) {
|
||||
var uuid UUID
|
||||
switch len(s) {
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36:
|
||||
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9:
|
||||
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
}
|
||||
s = s[9:]
|
||||
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
case 36 + 2:
|
||||
s = s[1:]
|
||||
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
case 32:
|
||||
var ok bool
|
||||
for i := range uuid {
|
||||
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
v, ok := xtob(s[x], s[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||
func ParseBytes(b []byte) (UUID, error) {
|
||||
var uuid UUID
|
||||
switch len(b) {
|
||||
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||
}
|
||||
b = b[9:]
|
||||
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
b = b[1:]
|
||||
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
var ok bool
|
||||
for i := 0; i < 32; i += 2 {
|
||||
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
for i, x := range [16]int{
|
||||
0, 2, 4, 6,
|
||||
9, 11,
|
||||
14, 16,
|
||||
19, 21,
|
||||
24, 26, 28, 30, 32, 34} {
|
||||
v, ok := xtob(b[x], b[x+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
uuid[i] = v
|
||||
}
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||
func MustParse(s string) UUID {
|
||||
uuid, err := Parse(s)
|
||||
if err != nil {
|
||||
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||
// does not have a length of 16. The bytes are copied from the slice.
|
||||
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||
err = uuid.UnmarshalBinary(b)
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
// Must returns uuid if err is nil and panics otherwise.
|
||||
func Must(uuid UUID, err error) UUID {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// String returns the string form of uuid, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
// , or "" if uuid is invalid.
|
||||
func (uuid UUID) String() string {
|
||||
var buf [36]byte
|
||||
encodeHex(buf[:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
// URN returns the RFC 2141 URN form of uuid,
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, or "" if uuid is invalid.
|
||||
func (uuid UUID) URN() string {
|
||||
var buf [36 + 9]byte
|
||||
copy(buf[:], "urn:uuid:")
|
||||
encodeHex(buf[9:], uuid)
|
||||
return string(buf[:])
|
||||
}
|
||||
|
||||
func encodeHex(dst []byte, uuid UUID) {
|
||||
hex.Encode(dst, uuid[:4])
|
||||
dst[8] = '-'
|
||||
hex.Encode(dst[9:13], uuid[4:6])
|
||||
dst[13] = '-'
|
||||
hex.Encode(dst[14:18], uuid[6:8])
|
||||
dst[18] = '-'
|
||||
hex.Encode(dst[19:23], uuid[8:10])
|
||||
dst[23] = '-'
|
||||
hex.Encode(dst[24:], uuid[10:])
|
||||
}
|
||||
|
||||
// Variant returns the variant encoded in uuid.
|
||||
func (uuid UUID) Variant() Variant {
|
||||
switch {
|
||||
case (uuid[8] & 0xc0) == 0x80:
|
||||
return RFC4122
|
||||
case (uuid[8] & 0xe0) == 0xc0:
|
||||
return Microsoft
|
||||
case (uuid[8] & 0xe0) == 0xe0:
|
||||
return Future
|
||||
default:
|
||||
return Reserved
|
||||
}
|
||||
}
|
||||
|
||||
// Version returns the version of uuid.
|
||||
func (uuid UUID) Version() Version {
|
||||
return Version(uuid[6] >> 4)
|
||||
}
|
||||
|
||||
func (v Version) String() string {
|
||||
if v > 15 {
|
||||
return fmt.Sprintf("BAD_VERSION_%d", v)
|
||||
}
|
||||
return fmt.Sprintf("VERSION_%d", v)
|
||||
}
|
||||
|
||||
func (v Variant) String() string {
|
||||
switch v {
|
||||
case RFC4122:
|
||||
return "RFC4122"
|
||||
case Reserved:
|
||||
return "Reserved"
|
||||
case Microsoft:
|
||||
return "Microsoft"
|
||||
case Future:
|
||||
return "Future"
|
||||
case Invalid:
|
||||
return "Invalid"
|
||||
}
|
||||
return fmt.Sprintf("BadVariant%d", int(v))
|
||||
}
|
||||
|
||||
// SetRand sets the random number generator to r, which implements io.Reader.
|
||||
// If r.Read returns an error when the package requests random data then
|
||||
// a panic will be issued.
|
||||
//
|
||||
// Calling SetRand with nil sets the random number generator to the default
|
||||
// generator.
|
||||
func SetRand(r io.Reader) {
|
||||
if r == nil {
|
||||
rander = rand.Reader
|
||||
return
|
||||
}
|
||||
rander = r
|
||||
}
|
44
vendor/github.com/google/uuid/version1.go
generated
vendored
Normal file
44
vendor/github.com/google/uuid/version1.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// NewUUID returns a Version 1 UUID based on the current NodeID and clock
|
||||
// sequence, and the current time. If the NodeID has not been set by SetNodeID
|
||||
// or SetNodeInterface then it will be set automatically. If the NodeID cannot
|
||||
// be set NewUUID returns nil. If clock sequence has not been set by
|
||||
// SetClockSequence then it will be set automatically. If GetTime fails to
|
||||
// return the current NewUUID returns nil and an error.
|
||||
//
|
||||
// In most cases, New should be used.
|
||||
func NewUUID() (UUID, error) {
|
||||
nodeMu.Lock()
|
||||
if nodeID == zeroID {
|
||||
setNodeInterface("")
|
||||
}
|
||||
nodeMu.Unlock()
|
||||
|
||||
var uuid UUID
|
||||
now, seq, err := GetTime()
|
||||
if err != nil {
|
||||
return uuid, err
|
||||
}
|
||||
|
||||
timeLow := uint32(now & 0xffffffff)
|
||||
timeMid := uint16((now >> 32) & 0xffff)
|
||||
timeHi := uint16((now >> 48) & 0x0fff)
|
||||
timeHi |= 0x1000 // Version 1
|
||||
|
||||
binary.BigEndian.PutUint32(uuid[0:], timeLow)
|
||||
binary.BigEndian.PutUint16(uuid[4:], timeMid)
|
||||
binary.BigEndian.PutUint16(uuid[6:], timeHi)
|
||||
binary.BigEndian.PutUint16(uuid[8:], seq)
|
||||
copy(uuid[10:], nodeID[:])
|
||||
|
||||
return uuid, nil
|
||||
}
|
38
vendor/github.com/google/uuid/version4.go
generated
vendored
Normal file
38
vendor/github.com/google/uuid/version4.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package uuid
|
||||
|
||||
import "io"
|
||||
|
||||
// New creates a new random UUID or panics. New is equivalent to
|
||||
// the expression
|
||||
//
|
||||
// uuid.Must(uuid.NewRandom())
|
||||
func New() UUID {
|
||||
return Must(NewRandom())
|
||||
}
|
||||
|
||||
// NewRandom returns a Random (Version 4) UUID.
|
||||
//
|
||||
// The strength of the UUIDs is based on the strength of the crypto/rand
|
||||
// package.
|
||||
//
|
||||
// A note about uniqueness derived from the UUID Wikipedia entry:
|
||||
//
|
||||
// Randomly generated UUIDs have 122 random bits. One's annual risk of being
|
||||
// hit by a meteorite is estimated to be one chance in 17 billion, that
|
||||
// means the probability is about 0.00000000006 (6 × 10−11),
|
||||
// equivalent to the odds of creating a few tens of trillions of UUIDs in a
|
||||
// year and having one duplicate.
|
||||
func NewRandom() (UUID, error) {
|
||||
var uuid UUID
|
||||
_, err := io.ReadFull(rander, uuid[:])
|
||||
if err != nil {
|
||||
return Nil, err
|
||||
}
|
||||
uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
|
||||
uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
|
||||
return uuid, nil
|
||||
}
|
1
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
1
vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
generated
vendored
@ -26,6 +26,7 @@ The tool is sponsored by the [marvin + konsorten GmbH](http://www.konsorten.de).
|
||||
We thank all the authors who provided code to this library:
|
||||
|
||||
* Felix Kollmann
|
||||
* Nicolas Perraut
|
||||
|
||||
## License
|
||||
|
||||
|
11
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
generated
vendored
Normal file
11
vendor/github.com/konsorten/go-windows-terminal-sequences/sequences_dummy.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
// +build linux darwin
|
||||
|
||||
package sequences
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func EnableVirtualTerminalProcessing(stream uintptr, enable bool) error {
|
||||
return fmt.Errorf("windows only package")
|
||||
}
|
191
vendor/github.com/mainflux/mproxy/LICENSE
generated
vendored
Normal file
191
vendor/github.com/mainflux/mproxy/LICENSE
generated
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Mainflux
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
28
vendor/github.com/mainflux/mproxy/pkg/events/events.go
generated
vendored
Normal file
28
vendor/github.com/mainflux/mproxy/pkg/events/events.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
package events
|
||||
|
||||
// Event is an interface for mProxy hooks
|
||||
type Event interface {
|
||||
// Authorization on client `CONNECT`
|
||||
// Each of the params are passed by reference, so that it can be changed
|
||||
AuthRegister(username, clientID *string, password *[]byte) error
|
||||
|
||||
// Authorization on client `PUBLISH`
|
||||
// Topic is passed by reference, so that it can be modified
|
||||
AuthPublish(username, clientID string, topic *string, payload *[]byte) error
|
||||
|
||||
// Authorization on client `SUBSCRIBE`
|
||||
// Topics are passed by reference, so that they can be modified
|
||||
AuthSubscribe(username, clientID string, topics *[]string) error
|
||||
|
||||
// After client successfully connected
|
||||
Register(clientID string)
|
||||
|
||||
// After client successfully published
|
||||
Publish(clientID, topic string, payload []byte)
|
||||
|
||||
// After client successfully subscribed
|
||||
Subscribe(clientID string, topics []string)
|
||||
|
||||
// After client unsubscribed
|
||||
Unsubscribe(clientID string, topics []string)
|
||||
}
|
82
vendor/github.com/mainflux/mproxy/pkg/mqtt/proxy.go
generated
vendored
Normal file
82
vendor/github.com/mainflux/mproxy/pkg/mqtt/proxy.go
generated
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
package mqtt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mproxy/pkg/events"
|
||||
)
|
||||
|
||||
// Proxy is main MQTT proxy struct
|
||||
type Proxy struct {
|
||||
host string
|
||||
port string
|
||||
target string
|
||||
event events.Event
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// New will setup a new Proxy struct after parsing the options
|
||||
func New(host, port, targetHost, targetPort string, event events.Event, logger logger.Logger) *Proxy {
|
||||
return &Proxy{
|
||||
host: host,
|
||||
port: port,
|
||||
target: fmt.Sprintf("%s:%s", targetHost, targetPort),
|
||||
event: event,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proxy) accept(l net.Listener) {
|
||||
for {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
p.logger.Warn("Accept error " + err.Error())
|
||||
continue
|
||||
}
|
||||
|
||||
p.logger.Info("Accepted new client")
|
||||
go p.handleConnection(conn)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proxy) handleConnection(inbound net.Conn) {
|
||||
defer inbound.Close()
|
||||
|
||||
outbound, err := net.Dial("tcp", p.target)
|
||||
if err != nil {
|
||||
p.logger.Error("Cannot connect to remote broker " + p.target)
|
||||
return
|
||||
}
|
||||
defer outbound.Close()
|
||||
|
||||
uuid, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s := newSession(uuid.String(), inbound, outbound, p.event, p.logger)
|
||||
if err := s.stream(); err != io.EOF {
|
||||
p.logger.Warn("Exited session " + s.id + "with error: " + err.Error())
|
||||
}
|
||||
s.logger.Info("Session " + s.id + "closed: " + s.outbound.LocalAddr().String())
|
||||
}
|
||||
|
||||
// Proxy of the server, this will block.
|
||||
func (p *Proxy) Proxy() error {
|
||||
addr := fmt.Sprintf("%s:%s", p.host, p.port)
|
||||
l, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
// Acceptor loop
|
||||
p.accept(l)
|
||||
|
||||
p.logger.Info("Server Exiting...")
|
||||
return nil
|
||||
}
|
114
vendor/github.com/mainflux/mproxy/pkg/mqtt/session.go
generated
vendored
Normal file
114
vendor/github.com/mainflux/mproxy/pkg/mqtt/session.go
generated
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
package mqtt
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/eclipse/paho.mqtt.golang/packets"
|
||||
"github.com/mainflux/mainflux/logger"
|
||||
"github.com/mainflux/mproxy/pkg/events"
|
||||
)
|
||||
|
||||
const (
|
||||
up direction = iota
|
||||
down
|
||||
)
|
||||
|
||||
type direction int
|
||||
|
||||
type mqttClient struct {
|
||||
ID string
|
||||
username string
|
||||
password []byte
|
||||
}
|
||||
|
||||
type session struct {
|
||||
id string
|
||||
logger logger.Logger
|
||||
inbound net.Conn
|
||||
outbound net.Conn
|
||||
event events.Event
|
||||
client mqttClient
|
||||
}
|
||||
|
||||
func newSession(uuid string, inbound, outbound net.Conn, event events.Event, logger logger.Logger) *session {
|
||||
return &session{
|
||||
id: uuid,
|
||||
logger: logger,
|
||||
inbound: inbound,
|
||||
outbound: outbound,
|
||||
event: event,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *session) stream() error {
|
||||
// In parallel read from client, send to broker
|
||||
// and read from broker, send to client
|
||||
errs := make(chan error, 2)
|
||||
|
||||
go s.streamUnidir(up, s.inbound, s.outbound, errs)
|
||||
go s.streamUnidir(down, s.outbound, s.inbound, errs)
|
||||
|
||||
return <-errs
|
||||
}
|
||||
|
||||
func (s *session) streamUnidir(dir direction, r, w net.Conn, errs chan error) {
|
||||
for {
|
||||
// Read from one connection
|
||||
pkt, err := packets.ReadPacket(r)
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
if dir == up {
|
||||
if err := s.authorize(pkt); err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Send to another
|
||||
if err := pkt.Write(w); err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
|
||||
if dir == up {
|
||||
s.notify(pkt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *session) authorize(pkt packets.ControlPacket) error {
|
||||
switch p := pkt.(type) {
|
||||
case *packets.ConnectPacket:
|
||||
if err := s.event.AuthRegister(&p.Username, &p.ClientIdentifier, &p.Password); err != nil {
|
||||
return err
|
||||
}
|
||||
s.client.username = p.Username
|
||||
s.client.password = p.Password
|
||||
s.client.ID = p.ClientIdentifier
|
||||
return nil
|
||||
case *packets.PublishPacket:
|
||||
return s.event.AuthPublish(s.client.username, s.client.ID, &p.TopicName, &p.Payload)
|
||||
case *packets.SubscribePacket:
|
||||
return s.event.AuthSubscribe(s.client.username, s.client.ID, &p.Topics)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *session) notify(pkt packets.ControlPacket) {
|
||||
switch p := pkt.(type) {
|
||||
case *packets.ConnectPacket:
|
||||
s.event.Register(s.client.ID)
|
||||
case *packets.PublishPacket:
|
||||
s.event.Publish(s.client.ID, p.TopicName, p.Payload)
|
||||
case *packets.SubscribePacket:
|
||||
s.event.Subscribe(s.client.ID, p.Topics)
|
||||
case *packets.UnsubscribePacket:
|
||||
s.event.Unsubscribe(s.client.ID, p.Topics)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
21
vendor/github.com/nats-io/go-nats/.travis.yml
generated
vendored
21
vendor/github.com/nats-io/go-nats/.travis.yml
generated
vendored
@ -1,21 +0,0 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.10.x
|
||||
- 1.9.x
|
||||
install:
|
||||
- go get -t ./...
|
||||
- go get github.com/nats-io/gnatsd
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get github.com/wadey/gocovmerge
|
||||
- go get -u honnef.co/go/tools/cmd/megacheck
|
||||
- go get -u github.com/client9/misspell/cmd/misspell
|
||||
before_script:
|
||||
- $(exit $(go fmt ./... | wc -l))
|
||||
- go vet ./...
|
||||
- misspell -error -locale US .
|
||||
- megacheck -ignore "$(cat staticcheck.ignore)" ./...
|
||||
script:
|
||||
- go test -i -race ./...
|
||||
- if [[ "$TRAVIS_GO_VERSION" == 1.11.* ]]; then ./scripts/cov.sh TRAVIS; else go test -v -race ./...; fi
|
4
vendor/github.com/nats-io/go-nats/staticcheck.ignore
generated
vendored
4
vendor/github.com/nats-io/go-nats/staticcheck.ignore
generated
vendored
@ -1,4 +0,0 @@
|
||||
github.com/nats-io/go-nats/*_test.go:SA2002
|
||||
github.com/nats-io/go-nats/*/*_test.go:SA2002
|
||||
github.com/nats-io/go-nats/test/context_test.go:SA1012
|
||||
github.com/nats-io/go-nats/nats.go:SA6000
|
16
vendor/github.com/nats-io/jwt/.gitignore
generated
vendored
Normal file
16
vendor/github.com/nats-io/jwt/.gitignore
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# IDE Files
|
||||
.vscode
|
||||
.idea/
|
22
vendor/github.com/nats-io/jwt/.travis.yml
generated
vendored
Normal file
22
vendor/github.com/nats-io/jwt/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.13.x
|
||||
- 1.12.x
|
||||
|
||||
install:
|
||||
- go get -t ./...
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get github.com/wadey/gocovmerge
|
||||
- go get -u honnef.co/go/tools/cmd/staticcheck
|
||||
- go get -u github.com/client9/misspell/cmd/misspell
|
||||
|
||||
before_script:
|
||||
- $(exit $(go fmt ./... | wc -l))
|
||||
- go vet ./...
|
||||
- misspell -error -locale US .
|
||||
- staticcheck ./...
|
||||
|
||||
script:
|
||||
- go test -v -race ./...
|
||||
- if [[ "$TRAVIS_GO_VERSION" =~ 1.12 ]]; then ./scripts/cov.sh TRAVIS; fi
|
0
vendor/github.com/nats-io/go-nats/LICENSE → vendor/github.com/nats-io/jwt/LICENSE
generated
vendored
0
vendor/github.com/nats-io/go-nats/LICENSE → vendor/github.com/nats-io/jwt/LICENSE
generated
vendored
19
vendor/github.com/nats-io/jwt/Makefile
generated
vendored
Normal file
19
vendor/github.com/nats-io/jwt/Makefile
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
.PHONY: test cover
|
||||
|
||||
build:
|
||||
go build
|
||||
|
||||
test:
|
||||
gofmt -s -w *.go
|
||||
goimports -w *.go
|
||||
go vet ./...
|
||||
go test -v
|
||||
go test -v --race
|
||||
staticcheck ./...
|
||||
|
||||
fmt:
|
||||
gofmt -w -s *.go
|
||||
|
||||
cover:
|
||||
go test -v -covermode=count -coverprofile=coverage.out
|
||||
go tool cover -html=coverage.out
|
54
vendor/github.com/nats-io/jwt/README.md
generated
vendored
Normal file
54
vendor/github.com/nats-io/jwt/README.md
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
# JWT
|
||||
A [JWT](https://jwt.io/) implementation that uses [nkeys](https://github.com/nats-io/nkeys) to digitally sign JWT tokens.
|
||||
Nkeys use [Ed25519](https://ed25519.cr.yp.to/) to provide authentication of JWT claims.
|
||||
|
||||
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
[](http://goreportcard.com/report/nats-io/jwt)
|
||||
[](http://travis-ci.org/nats-io/jwt)
|
||||
[](http://godoc.org/github.com/nats-io/jwt)
|
||||
[](https://coveralls.io/github/nats-io/jwt?branch=master)
|
||||
|
||||
```go
|
||||
// Need a private key to sign the claim, nkeys makes it easy to create
|
||||
kp, err := nkeys.CreateAccount()
|
||||
if err != nil {
|
||||
t.Fatal("unable to create account key", err)
|
||||
}
|
||||
|
||||
pk, err := kp.PublicKey()
|
||||
if err != nil {
|
||||
t.Fatal("error getting public key", err)
|
||||
}
|
||||
|
||||
// create a new claim
|
||||
claims := NewAccountClaims(pk)
|
||||
claims.Expires = time.Now().Add(time.Duration(time.Hour)).Unix()
|
||||
|
||||
|
||||
// add details by modifying claims.Account
|
||||
|
||||
// serialize the claim to a JWT token
|
||||
token, err := claims.Encode(kp)
|
||||
if err != nil {
|
||||
t.Fatal("error encoding token", err)
|
||||
}
|
||||
|
||||
// on the receiving side, decode the token
|
||||
c, err := DecodeAccountClaims(token)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// if the token was decoded, it means that it
|
||||
// validated and it wasn't tampered. the remaining and
|
||||
// required test is to insure the issuer is trusted
|
||||
pk, err := kp.PublicKey()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to read public key: %v", err)
|
||||
}
|
||||
|
||||
if c.Issuer != pk {
|
||||
t.Fatalf("the public key is not trusted")
|
||||
}
|
||||
```
|
5
vendor/github.com/nats-io/jwt/ReleaseNotes.md
generated
vendored
Normal file
5
vendor/github.com/nats-io/jwt/ReleaseNotes.md
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Release Notes
|
||||
|
||||
## 0.3.0
|
||||
|
||||
* Removed revocation claims in favor of timestamp-based revocation maps in account and export claims.
|
222
vendor/github.com/nats-io/jwt/account_claims.go
generated
vendored
Normal file
222
vendor/github.com/nats-io/jwt/account_claims.go
generated
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 2018-2019 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// NoLimit is used to indicate a limit field is unlimited in value.
|
||||
const NoLimit = -1
|
||||
|
||||
// OperatorLimits are used to limit access by an account
|
||||
type OperatorLimits struct {
|
||||
Subs int64 `json:"subs,omitempty"` // Max number of subscriptions
|
||||
Conn int64 `json:"conn,omitempty"` // Max number of active connections
|
||||
LeafNodeConn int64 `json:"leaf,omitempty"` // Max number of active leaf node connections
|
||||
Imports int64 `json:"imports,omitempty"` // Max number of imports
|
||||
Exports int64 `json:"exports,omitempty"` // Max number of exports
|
||||
Data int64 `json:"data,omitempty"` // Max number of bytes
|
||||
Payload int64 `json:"payload,omitempty"` // Max message payload
|
||||
WildcardExports bool `json:"wildcards,omitempty"` // Are wildcards allowed in exports
|
||||
}
|
||||
|
||||
// IsEmpty returns true if all of the limits are 0/false.
|
||||
func (o *OperatorLimits) IsEmpty() bool {
|
||||
return *o == OperatorLimits{}
|
||||
}
|
||||
|
||||
// IsUnlimited returns true if all limits are
|
||||
func (o *OperatorLimits) IsUnlimited() bool {
|
||||
return *o == OperatorLimits{NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, true}
|
||||
}
|
||||
|
||||
// Validate checks that the operator limits contain valid values
|
||||
func (o *OperatorLimits) Validate(vr *ValidationResults) {
|
||||
// negative values mean unlimited, so all numbers are valid
|
||||
}
|
||||
|
||||
// Account holds account specific claims data
|
||||
type Account struct {
|
||||
Imports Imports `json:"imports,omitempty"`
|
||||
Exports Exports `json:"exports,omitempty"`
|
||||
Identities []Identity `json:"identity,omitempty"`
|
||||
Limits OperatorLimits `json:"limits,omitempty"`
|
||||
SigningKeys StringList `json:"signing_keys,omitempty"`
|
||||
Revocations RevocationList `json:"revocations,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks if the account is valid, based on the wrapper
|
||||
func (a *Account) Validate(acct *AccountClaims, vr *ValidationResults) {
|
||||
a.Imports.Validate(acct.Subject, vr)
|
||||
a.Exports.Validate(vr)
|
||||
a.Limits.Validate(vr)
|
||||
|
||||
for _, i := range a.Identities {
|
||||
i.Validate(vr)
|
||||
}
|
||||
|
||||
if !a.Limits.IsEmpty() && a.Limits.Imports >= 0 && int64(len(a.Imports)) > a.Limits.Imports {
|
||||
vr.AddError("the account contains more imports than allowed by the operator")
|
||||
}
|
||||
|
||||
// Check Imports and Exports for limit violations.
|
||||
if a.Limits.Imports != NoLimit {
|
||||
if int64(len(a.Imports)) > a.Limits.Imports {
|
||||
vr.AddError("the account contains more imports than allowed by the operator")
|
||||
}
|
||||
}
|
||||
if a.Limits.Exports != NoLimit {
|
||||
if int64(len(a.Exports)) > a.Limits.Exports {
|
||||
vr.AddError("the account contains more exports than allowed by the operator")
|
||||
}
|
||||
// Check for wildcard restrictions
|
||||
if !a.Limits.WildcardExports {
|
||||
for _, ex := range a.Exports {
|
||||
if ex.Subject.HasWildCards() {
|
||||
vr.AddError("the account contains wildcard exports that are not allowed by the operator")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, k := range a.SigningKeys {
|
||||
if !nkeys.IsValidPublicAccountKey(k) {
|
||||
vr.AddError("%s is not an account public key", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AccountClaims defines the body of an account JWT
|
||||
type AccountClaims struct {
|
||||
ClaimsData
|
||||
Account `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewAccountClaims creates a new account JWT
|
||||
func NewAccountClaims(subject string) *AccountClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &AccountClaims{}
|
||||
// Set to unlimited to start. We do it this way so we get compiler
|
||||
// errors if we add to the OperatorLimits.
|
||||
c.Limits = OperatorLimits{NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, NoLimit, true}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// Encode converts account claims into a JWT string
|
||||
func (a *AccountClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicAccountKey(a.Subject) {
|
||||
return "", errors.New("expected subject to be account public key")
|
||||
}
|
||||
sort.Sort(a.Exports)
|
||||
sort.Sort(a.Imports)
|
||||
a.ClaimsData.Type = AccountClaim
|
||||
return a.ClaimsData.Encode(pair, a)
|
||||
}
|
||||
|
||||
// DecodeAccountClaims decodes account claims from a JWT string
|
||||
func DecodeAccountClaims(token string) (*AccountClaims, error) {
|
||||
v := AccountClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (a *AccountClaims) String() string {
|
||||
return a.ClaimsData.String(a)
|
||||
}
|
||||
|
||||
// Payload pulls the accounts specific payload out of the claims
|
||||
func (a *AccountClaims) Payload() interface{} {
|
||||
return &a.Account
|
||||
}
|
||||
|
||||
// Validate checks the accounts contents
|
||||
func (a *AccountClaims) Validate(vr *ValidationResults) {
|
||||
a.ClaimsData.Validate(vr)
|
||||
a.Account.Validate(a, vr)
|
||||
|
||||
if nkeys.IsValidPublicAccountKey(a.ClaimsData.Issuer) {
|
||||
if len(a.Identities) > 0 {
|
||||
vr.AddWarning("self-signed account JWTs shouldn't contain identity proofs")
|
||||
}
|
||||
if !a.Limits.IsEmpty() {
|
||||
vr.AddWarning("self-signed account JWTs shouldn't contain operator limits")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can encode an account jwt, account and operator
|
||||
func (a *AccountClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteAccount, nkeys.PrefixByteOperator}
|
||||
}
|
||||
|
||||
// Claims returns the accounts claims data
|
||||
func (a *AccountClaims) Claims() *ClaimsData {
|
||||
return &a.ClaimsData
|
||||
}
|
||||
|
||||
// DidSign checks the claims against the account's public key and its signing keys
|
||||
func (a *AccountClaims) DidSign(op Claims) bool {
|
||||
if op != nil {
|
||||
issuer := op.Claims().Issuer
|
||||
if issuer == a.Subject {
|
||||
return true
|
||||
}
|
||||
return a.SigningKeys.Contains(issuer)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Revoke enters a revocation by publickey using time.Now().
|
||||
func (a *AccountClaims) Revoke(pubKey string) {
|
||||
a.RevokeAt(pubKey, time.Now())
|
||||
}
|
||||
|
||||
// RevokeAt enters a revocation by publickey and timestamp into this export
|
||||
// If there is already a revocation for this public key that is newer, it is kept.
|
||||
func (a *AccountClaims) RevokeAt(pubKey string, timestamp time.Time) {
|
||||
if a.Revocations == nil {
|
||||
a.Revocations = RevocationList{}
|
||||
}
|
||||
|
||||
a.Revocations.Revoke(pubKey, timestamp)
|
||||
}
|
||||
|
||||
// ClearRevocation removes any revocation for the public key
|
||||
func (a *AccountClaims) ClearRevocation(pubKey string) {
|
||||
a.Revocations.ClearRevocation(pubKey)
|
||||
}
|
||||
|
||||
// IsRevokedAt checks if the public key is in the revoked list with a timestamp later than
|
||||
// the one passed in. Generally this method is called with time.Now() but other time's can
|
||||
// be used for testing.
|
||||
func (a *AccountClaims) IsRevokedAt(pubKey string, timestamp time.Time) bool {
|
||||
return a.Revocations.IsRevoked(pubKey, timestamp)
|
||||
}
|
||||
|
||||
// IsRevoked checks if the public key is in the revoked list with time.Now()
|
||||
func (a *AccountClaims) IsRevoked(pubKey string) bool {
|
||||
return a.Revocations.IsRevoked(pubKey, time.Now())
|
||||
}
|
166
vendor/github.com/nats-io/jwt/activation_claims.go
generated
vendored
Normal file
166
vendor/github.com/nats-io/jwt/activation_claims.go
generated
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2018 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base32"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// Activation defines the custom parts of an activation claim
|
||||
type Activation struct {
|
||||
ImportSubject Subject `json:"subject,omitempty"`
|
||||
ImportType ExportType `json:"type,omitempty"`
|
||||
Limits
|
||||
}
|
||||
|
||||
// IsService returns true if an Activation is for a service
|
||||
func (a *Activation) IsService() bool {
|
||||
return a.ImportType == Service
|
||||
}
|
||||
|
||||
// IsStream returns true if an Activation is for a stream
|
||||
func (a *Activation) IsStream() bool {
|
||||
return a.ImportType == Stream
|
||||
}
|
||||
|
||||
// Validate checks the exports and limits in an activation JWT
|
||||
func (a *Activation) Validate(vr *ValidationResults) {
|
||||
if !a.IsService() && !a.IsStream() {
|
||||
vr.AddError("invalid export type: %q", a.ImportType)
|
||||
}
|
||||
|
||||
if a.IsService() {
|
||||
if a.ImportSubject.HasWildCards() {
|
||||
vr.AddError("services cannot have wildcard subject: %q", a.ImportSubject)
|
||||
}
|
||||
}
|
||||
|
||||
a.ImportSubject.Validate(vr)
|
||||
a.Limits.Validate(vr)
|
||||
}
|
||||
|
||||
// ActivationClaims holds the data specific to an activation JWT
|
||||
type ActivationClaims struct {
|
||||
ClaimsData
|
||||
Activation `json:"nats,omitempty"`
|
||||
// IssuerAccount stores the public key for the account the issuer represents.
|
||||
// When set, the claim was issued by a signing key.
|
||||
IssuerAccount string `json:"issuer_account,omitempty"`
|
||||
}
|
||||
|
||||
// NewActivationClaims creates a new activation claim with the provided sub
|
||||
func NewActivationClaims(subject string) *ActivationClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
ac := &ActivationClaims{}
|
||||
ac.Subject = subject
|
||||
return ac
|
||||
}
|
||||
|
||||
// Encode turns an activation claim into a JWT strimg
|
||||
func (a *ActivationClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicAccountKey(a.ClaimsData.Subject) {
|
||||
return "", errors.New("expected subject to be an account")
|
||||
}
|
||||
a.ClaimsData.Type = ActivationClaim
|
||||
return a.ClaimsData.Encode(pair, a)
|
||||
}
|
||||
|
||||
// DecodeActivationClaims tries to create an activation claim from a JWT string
|
||||
func DecodeActivationClaims(token string) (*ActivationClaims, error) {
|
||||
v := ActivationClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
// Payload returns the activation specific part of the JWT
|
||||
func (a *ActivationClaims) Payload() interface{} {
|
||||
return a.Activation
|
||||
}
|
||||
|
||||
// Validate checks the claims
|
||||
func (a *ActivationClaims) Validate(vr *ValidationResults) {
|
||||
a.ClaimsData.Validate(vr)
|
||||
a.Activation.Validate(vr)
|
||||
if a.IssuerAccount != "" && !nkeys.IsValidPublicAccountKey(a.IssuerAccount) {
|
||||
vr.AddError("account_id is not an account public key")
|
||||
}
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can sign an activation jwt, account and oeprator
|
||||
func (a *ActivationClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteAccount, nkeys.PrefixByteOperator}
|
||||
}
|
||||
|
||||
// Claims returns the generic part of the JWT
|
||||
func (a *ActivationClaims) Claims() *ClaimsData {
|
||||
return &a.ClaimsData
|
||||
}
|
||||
|
||||
func (a *ActivationClaims) String() string {
|
||||
return a.ClaimsData.String(a)
|
||||
}
|
||||
|
||||
// HashID returns a hash of the claims that can be used to identify it.
|
||||
// The hash is calculated by creating a string with
|
||||
// issuerPubKey.subjectPubKey.<subject> and constructing the sha-256 hash and base32 encoding that.
|
||||
// <subject> is the exported subject, minus any wildcards, so foo.* becomes foo.
|
||||
// the one special case is that if the export start with "*" or is ">" the <subject> "_"
|
||||
func (a *ActivationClaims) HashID() (string, error) {
|
||||
|
||||
if a.Issuer == "" || a.Subject == "" || a.ImportSubject == "" {
|
||||
return "", fmt.Errorf("not enough data in the activaion claims to create a hash")
|
||||
}
|
||||
|
||||
subject := cleanSubject(string(a.ImportSubject))
|
||||
base := fmt.Sprintf("%s.%s.%s", a.Issuer, a.Subject, subject)
|
||||
h := sha256.New()
|
||||
h.Write([]byte(base))
|
||||
sha := h.Sum(nil)
|
||||
hash := base32.StdEncoding.EncodeToString(sha)
|
||||
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func cleanSubject(subject string) string {
|
||||
split := strings.Split(subject, ".")
|
||||
cleaned := ""
|
||||
|
||||
for i, tok := range split {
|
||||
if tok == "*" || tok == ">" {
|
||||
if i == 0 {
|
||||
cleaned = "_"
|
||||
break
|
||||
}
|
||||
|
||||
cleaned = strings.Join(split[:i], ".")
|
||||
break
|
||||
}
|
||||
}
|
||||
if cleaned == "" {
|
||||
cleaned = subject
|
||||
}
|
||||
return cleaned
|
||||
}
|
302
vendor/github.com/nats-io/jwt/claims.go
generated
vendored
Normal file
302
vendor/github.com/nats-io/jwt/claims.go
generated
vendored
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright 2018-2019 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// ClaimType is used to indicate the type of JWT being stored in a Claim
|
||||
type ClaimType string
|
||||
|
||||
const (
|
||||
// AccountClaim is the type of an Account JWT
|
||||
AccountClaim = "account"
|
||||
//ActivationClaim is the type of an activation JWT
|
||||
ActivationClaim = "activation"
|
||||
//UserClaim is the type of an user JWT
|
||||
UserClaim = "user"
|
||||
//ServerClaim is the type of an server JWT
|
||||
ServerClaim = "server"
|
||||
//ClusterClaim is the type of an cluster JWT
|
||||
ClusterClaim = "cluster"
|
||||
//OperatorClaim is the type of an operator JWT
|
||||
OperatorClaim = "operator"
|
||||
)
|
||||
|
||||
// Claims is a JWT claims
|
||||
type Claims interface {
|
||||
Claims() *ClaimsData
|
||||
Encode(kp nkeys.KeyPair) (string, error)
|
||||
ExpectedPrefixes() []nkeys.PrefixByte
|
||||
Payload() interface{}
|
||||
String() string
|
||||
Validate(vr *ValidationResults)
|
||||
Verify(payload string, sig []byte) bool
|
||||
}
|
||||
|
||||
// ClaimsData is the base struct for all claims
|
||||
type ClaimsData struct {
|
||||
Audience string `json:"aud,omitempty"`
|
||||
Expires int64 `json:"exp,omitempty"`
|
||||
ID string `json:"jti,omitempty"`
|
||||
IssuedAt int64 `json:"iat,omitempty"`
|
||||
Issuer string `json:"iss,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
NotBefore int64 `json:"nbf,omitempty"`
|
||||
Subject string `json:"sub,omitempty"`
|
||||
Tags TagList `json:"tags,omitempty"`
|
||||
Type ClaimType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// Prefix holds the prefix byte for an NKey
|
||||
type Prefix struct {
|
||||
nkeys.PrefixByte
|
||||
}
|
||||
|
||||
func encodeToString(d []byte) string {
|
||||
return base64.RawURLEncoding.EncodeToString(d)
|
||||
}
|
||||
|
||||
func decodeString(s string) ([]byte, error) {
|
||||
return base64.RawURLEncoding.DecodeString(s)
|
||||
}
|
||||
|
||||
func serialize(v interface{}) (string, error) {
|
||||
j, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return encodeToString(j), nil
|
||||
}
|
||||
|
||||
func (c *ClaimsData) doEncode(header *Header, kp nkeys.KeyPair, claim Claims) (string, error) {
|
||||
if header == nil {
|
||||
return "", errors.New("header is required")
|
||||
}
|
||||
|
||||
if kp == nil {
|
||||
return "", errors.New("keypair is required")
|
||||
}
|
||||
|
||||
if c.Subject == "" {
|
||||
return "", errors.New("subject is not set")
|
||||
}
|
||||
|
||||
h, err := serialize(header)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
issuerBytes, err := kp.PublicKey()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
prefixes := claim.ExpectedPrefixes()
|
||||
if prefixes != nil {
|
||||
ok := false
|
||||
for _, p := range prefixes {
|
||||
switch p {
|
||||
case nkeys.PrefixByteAccount:
|
||||
if nkeys.IsValidPublicAccountKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteOperator:
|
||||
if nkeys.IsValidPublicOperatorKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteServer:
|
||||
if nkeys.IsValidPublicServerKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteCluster:
|
||||
if nkeys.IsValidPublicClusterKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteUser:
|
||||
if nkeys.IsValidPublicUserKey(issuerBytes) {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unable to validate expected prefixes - %v", prefixes)
|
||||
}
|
||||
}
|
||||
|
||||
c.Issuer = string(issuerBytes)
|
||||
c.IssuedAt = time.Now().UTC().Unix()
|
||||
|
||||
c.ID, err = c.hash()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
payload, err := serialize(claim)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
sig, err := kp.Sign([]byte(payload))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
eSig := encodeToString(sig)
|
||||
return fmt.Sprintf("%s.%s.%s", h, payload, eSig), nil
|
||||
}
|
||||
|
||||
func (c *ClaimsData) hash() (string, error) {
|
||||
j, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
h := sha512.New512_256()
|
||||
h.Write(j)
|
||||
return base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
|
||||
// Encode encodes a claim into a JWT token. The claim is signed with the
|
||||
// provided nkey's private key
|
||||
func (c *ClaimsData) Encode(kp nkeys.KeyPair, payload Claims) (string, error) {
|
||||
return c.doEncode(&Header{TokenTypeJwt, AlgorithmNkey}, kp, payload)
|
||||
}
|
||||
|
||||
// Returns a JSON representation of the claim
|
||||
func (c *ClaimsData) String(claim interface{}) string {
|
||||
j, err := json.MarshalIndent(claim, "", " ")
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(j)
|
||||
}
|
||||
|
||||
func parseClaims(s string, target Claims) error {
|
||||
h, err := decodeString(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(h, &target)
|
||||
}
|
||||
|
||||
// Verify verifies that the encoded payload was signed by the
|
||||
// provided public key. Verify is called automatically with
|
||||
// the claims portion of the token and the public key in the claim.
|
||||
// Client code need to insure that the public key in the
|
||||
// claim is trusted.
|
||||
func (c *ClaimsData) Verify(payload string, sig []byte) bool {
|
||||
// decode the public key
|
||||
kp, err := nkeys.FromPublicKey(c.Issuer)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if err := kp.Verify([]byte(payload), sig); err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Validate checks a claim to make sure it is valid. Validity checks
|
||||
// include expiration and not before constraints.
|
||||
func (c *ClaimsData) Validate(vr *ValidationResults) {
|
||||
now := time.Now().UTC().Unix()
|
||||
if c.Expires > 0 && now > c.Expires {
|
||||
vr.AddTimeCheck("claim is expired")
|
||||
}
|
||||
|
||||
if c.NotBefore > 0 && c.NotBefore > now {
|
||||
vr.AddTimeCheck("claim is not yet valid")
|
||||
}
|
||||
}
|
||||
|
||||
// IsSelfSigned returns true if the claims issuer is the subject
|
||||
func (c *ClaimsData) IsSelfSigned() bool {
|
||||
return c.Issuer == c.Subject
|
||||
}
|
||||
|
||||
// Decode takes a JWT string decodes it and validates it
|
||||
// and return the embedded Claims. If the token header
|
||||
// doesn't match the expected algorithm, or the claim is
|
||||
// not valid or verification fails an error is returned.
|
||||
func Decode(token string, target Claims) error {
|
||||
// must have 3 chunks
|
||||
chunks := strings.Split(token, ".")
|
||||
if len(chunks) != 3 {
|
||||
return errors.New("expected 3 chunks")
|
||||
}
|
||||
|
||||
_, err := parseHeaders(chunks[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := parseClaims(chunks[1], target); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sig, err := decodeString(chunks[2])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !target.Verify(chunks[1], sig) {
|
||||
return errors.New("claim failed signature verification")
|
||||
}
|
||||
|
||||
prefixes := target.ExpectedPrefixes()
|
||||
if prefixes != nil {
|
||||
ok := false
|
||||
issuer := target.Claims().Issuer
|
||||
for _, p := range prefixes {
|
||||
switch p {
|
||||
case nkeys.PrefixByteAccount:
|
||||
if nkeys.IsValidPublicAccountKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteOperator:
|
||||
if nkeys.IsValidPublicOperatorKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteServer:
|
||||
if nkeys.IsValidPublicServerKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteCluster:
|
||||
if nkeys.IsValidPublicClusterKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
case nkeys.PrefixByteUser:
|
||||
if nkeys.IsValidPublicUserKey(issuer) {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("unable to validate expected prefixes - %v", prefixes)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
94
vendor/github.com/nats-io/jwt/cluster_claims.go
generated
vendored
Normal file
94
vendor/github.com/nats-io/jwt/cluster_claims.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2018 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// Cluster stores the cluster specific elements of a cluster JWT
|
||||
type Cluster struct {
|
||||
Trust []string `json:"identity,omitempty"`
|
||||
Accounts []string `json:"accts,omitempty"`
|
||||
AccountURL string `json:"accturl,omitempty"`
|
||||
OperatorURL string `json:"opurl,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the cluster and permissions for a cluster JWT
|
||||
func (c *Cluster) Validate(vr *ValidationResults) {
|
||||
// fixme validate cluster data
|
||||
}
|
||||
|
||||
// ClusterClaims defines the data in a cluster JWT
|
||||
type ClusterClaims struct {
|
||||
ClaimsData
|
||||
Cluster `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewClusterClaims creates a new cluster JWT with the specified subject/public key
|
||||
func NewClusterClaims(subject string) *ClusterClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &ClusterClaims{}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// Encode tries to turn the cluster claims into a JWT string
|
||||
func (c *ClusterClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicClusterKey(c.Subject) {
|
||||
return "", errors.New("expected subject to be a cluster public key")
|
||||
}
|
||||
c.ClaimsData.Type = ClusterClaim
|
||||
return c.ClaimsData.Encode(pair, c)
|
||||
}
|
||||
|
||||
// DecodeClusterClaims tries to parse cluster claims from a JWT string
|
||||
func DecodeClusterClaims(token string) (*ClusterClaims, error) {
|
||||
v := ClusterClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (c *ClusterClaims) String() string {
|
||||
return c.ClaimsData.String(c)
|
||||
}
|
||||
|
||||
// Payload returns the cluster specific data
|
||||
func (c *ClusterClaims) Payload() interface{} {
|
||||
return &c.Cluster
|
||||
}
|
||||
|
||||
// Validate checks the generic and cluster data in the cluster claims
|
||||
func (c *ClusterClaims) Validate(vr *ValidationResults) {
|
||||
c.ClaimsData.Validate(vr)
|
||||
c.Cluster.Validate(vr)
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can encode a cluster JWT, operator or cluster
|
||||
func (c *ClusterClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteOperator, nkeys.PrefixByteCluster}
|
||||
}
|
||||
|
||||
// Claims returns the generic data
|
||||
func (c *ClusterClaims) Claims() *ClaimsData {
|
||||
return &c.ClaimsData
|
||||
}
|
203
vendor/github.com/nats-io/jwt/creds_utils.go
generated
vendored
Normal file
203
vendor/github.com/nats-io/jwt/creds_utils.go
generated
vendored
Normal file
@ -0,0 +1,203 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// DecorateJWT returns a decorated JWT that describes the kind of JWT
|
||||
func DecorateJWT(jwtString string) ([]byte, error) {
|
||||
gc, err := DecodeGeneric(jwtString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return formatJwt(string(gc.Type), jwtString)
|
||||
}
|
||||
|
||||
func formatJwt(kind string, jwtString string) ([]byte, error) {
|
||||
templ := `-----BEGIN NATS %s JWT-----
|
||||
%s
|
||||
------END NATS %s JWT------
|
||||
|
||||
`
|
||||
w := bytes.NewBuffer(nil)
|
||||
kind = strings.ToUpper(kind)
|
||||
_, err := fmt.Fprintf(w, templ, kind, jwtString, kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
// DecorateSeed takes a seed and returns a string that wraps
|
||||
// the seed in the form:
|
||||
// ************************* IMPORTANT *************************
|
||||
// NKEY Seed printed below can be used sign and prove identity.
|
||||
// NKEYs are sensitive and should be treated as secrets.
|
||||
//
|
||||
// -----BEGIN USER NKEY SEED-----
|
||||
// SUAIO3FHUX5PNV2LQIIP7TZ3N4L7TX3W53MQGEIVYFIGA635OZCKEYHFLM
|
||||
// ------END USER NKEY SEED------
|
||||
func DecorateSeed(seed []byte) ([]byte, error) {
|
||||
w := bytes.NewBuffer(nil)
|
||||
ts := bytes.TrimSpace(seed)
|
||||
pre := string(ts[0:2])
|
||||
kind := ""
|
||||
switch pre {
|
||||
case "SU":
|
||||
kind = "USER"
|
||||
case "SA":
|
||||
kind = "ACCOUNT"
|
||||
case "SO":
|
||||
kind = "OPERATOR"
|
||||
default:
|
||||
return nil, errors.New("seed is not an operator, account or user seed")
|
||||
}
|
||||
header := `************************* IMPORTANT *************************
|
||||
NKEY Seed printed below can be used to sign and prove identity.
|
||||
NKEYs are sensitive and should be treated as secrets.
|
||||
|
||||
-----BEGIN %s NKEY SEED-----
|
||||
`
|
||||
_, err := fmt.Fprintf(w, header, kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w.Write(ts)
|
||||
|
||||
footer := `
|
||||
------END %s NKEY SEED------
|
||||
|
||||
*************************************************************
|
||||
`
|
||||
_, err = fmt.Fprintf(w, footer, kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
var userConfigRE = regexp.MustCompile(`\s*(?:(?:[-]{3,}[^\n]*[-]{3,}\n)(.+)(?:\n\s*[-]{3,}[^\n]*[-]{3,}\n))`)
|
||||
|
||||
// An user config file looks like this:
|
||||
// -----BEGIN NATS USER JWT-----
|
||||
// eyJ0eXAiOiJqd3QiLCJhbGciOiJlZDI1NTE5...
|
||||
// ------END NATS USER JWT------
|
||||
//
|
||||
// ************************* IMPORTANT *************************
|
||||
// NKEY Seed printed below can be used sign and prove identity.
|
||||
// NKEYs are sensitive and should be treated as secrets.
|
||||
//
|
||||
// -----BEGIN USER NKEY SEED-----
|
||||
// SUAIO3FHUX5PNV2LQIIP7TZ3N4L7TX3W53MQGEIVYFIGA635OZCKEYHFLM
|
||||
// ------END USER NKEY SEED------
|
||||
|
||||
// FormatUserConfig returns a decorated file with a decorated JWT and decorated seed
|
||||
func FormatUserConfig(jwtString string, seed []byte) ([]byte, error) {
|
||||
gc, err := DecodeGeneric(jwtString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if gc.Type != UserClaim {
|
||||
return nil, fmt.Errorf("%q cannot be serialized as a user config", string(gc.Type))
|
||||
}
|
||||
|
||||
w := bytes.NewBuffer(nil)
|
||||
|
||||
jd, err := formatJwt(string(gc.Type), jwtString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = w.Write(jd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !bytes.HasPrefix(bytes.TrimSpace(seed), []byte("SU")) {
|
||||
return nil, fmt.Errorf("nkey seed is not an user seed")
|
||||
}
|
||||
|
||||
d, err := DecorateSeed(seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = w.Write(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return w.Bytes(), nil
|
||||
}
|
||||
|
||||
// ParseDecoratedJWT takes a creds file and returns the JWT portion.
|
||||
func ParseDecoratedJWT(contents []byte) (string, error) {
|
||||
items := userConfigRE.FindAllSubmatch(contents, -1)
|
||||
if len(items) == 0 {
|
||||
return string(contents), nil
|
||||
}
|
||||
// First result should be the user JWT.
|
||||
// We copy here so that if the file contained a seed file too we wipe appropriately.
|
||||
raw := items[0][1]
|
||||
tmp := make([]byte, len(raw))
|
||||
copy(tmp, raw)
|
||||
return string(tmp), nil
|
||||
}
|
||||
|
||||
// ParseDecoratedNKey takes a creds file, finds the NKey portion and creates a
|
||||
// key pair from it.
|
||||
func ParseDecoratedNKey(contents []byte) (nkeys.KeyPair, error) {
|
||||
var seed []byte
|
||||
|
||||
items := userConfigRE.FindAllSubmatch(contents, -1)
|
||||
if len(items) > 1 {
|
||||
seed = items[1][1]
|
||||
} else {
|
||||
lines := bytes.Split(contents, []byte("\n"))
|
||||
for _, line := range lines {
|
||||
if bytes.HasPrefix(bytes.TrimSpace(line), []byte("SO")) ||
|
||||
bytes.HasPrefix(bytes.TrimSpace(line), []byte("SA")) ||
|
||||
bytes.HasPrefix(bytes.TrimSpace(line), []byte("SU")) {
|
||||
seed = line
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if seed == nil {
|
||||
return nil, errors.New("no nkey seed found")
|
||||
}
|
||||
if !bytes.HasPrefix(seed, []byte("SO")) &&
|
||||
!bytes.HasPrefix(seed, []byte("SA")) &&
|
||||
!bytes.HasPrefix(seed, []byte("SU")) {
|
||||
return nil, errors.New("doesn't contain a seed nkey")
|
||||
}
|
||||
kp, err := nkeys.FromSeed(seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kp, nil
|
||||
}
|
||||
|
||||
// ParseDecoratedUserNKey takes a creds file, finds the NKey portion and creates a
|
||||
// key pair from it. Similar to ParseDecoratedNKey but fails for non-user keys.
|
||||
func ParseDecoratedUserNKey(contents []byte) (nkeys.KeyPair, error) {
|
||||
nk, err := ParseDecoratedNKey(contents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
seed, err := nk.Seed()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !bytes.HasPrefix(seed, []byte("SU")) {
|
||||
return nil, errors.New("doesn't contain an user seed nkey")
|
||||
}
|
||||
kp, err := nkeys.FromSeed(seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return kp, nil
|
||||
}
|
236
vendor/github.com/nats-io/jwt/exports.go
generated
vendored
Normal file
236
vendor/github.com/nats-io/jwt/exports.go
generated
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright 2018-2019 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ResponseType is used to store an export response type
|
||||
type ResponseType string
|
||||
|
||||
const (
|
||||
// ResponseTypeSingleton is used for a service that sends a single response only
|
||||
ResponseTypeSingleton = "Singleton"
|
||||
|
||||
// ResponseTypeStream is used for a service that will send multiple responses
|
||||
ResponseTypeStream = "Stream"
|
||||
|
||||
// ResponseTypeChunked is used for a service that sends a single response in chunks (so not quite a stream)
|
||||
ResponseTypeChunked = "Chunked"
|
||||
)
|
||||
|
||||
// ServiceLatency is used when observing and exported service for
|
||||
// latency measurements.
|
||||
// Sampling 1-100, represents sampling rate, defaults to 100.
|
||||
// Results is the subject where the latency metrics are published.
|
||||
// A metric will be defined by the nats-server's ServiceLatency. Time durations
|
||||
// are in nanoseconds.
|
||||
// see https://github.com/nats-io/nats-server/blob/master/server/accounts.go#L524
|
||||
// e.g.
|
||||
// {
|
||||
// "app": "dlc22",
|
||||
// "start": "2019-09-16T21:46:23.636869585-07:00",
|
||||
// "svc": 219732,
|
||||
// "nats": {
|
||||
// "req": 320415,
|
||||
// "resp": 228268,
|
||||
// "sys": 0
|
||||
// },
|
||||
// "total": 768415
|
||||
// }
|
||||
//
|
||||
type ServiceLatency struct {
|
||||
Sampling int `json:"sampling,omitempty"`
|
||||
Results Subject `json:"results"`
|
||||
}
|
||||
|
||||
func (sl *ServiceLatency) Validate(vr *ValidationResults) {
|
||||
if sl.Sampling < 1 || sl.Sampling > 100 {
|
||||
vr.AddError("sampling percentage needs to be between 1-100")
|
||||
}
|
||||
sl.Results.Validate(vr)
|
||||
if sl.Results.HasWildCards() {
|
||||
vr.AddError("results subject can not contain wildcards")
|
||||
}
|
||||
}
|
||||
|
||||
// Export represents a single export
|
||||
type Export struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Subject Subject `json:"subject,omitempty"`
|
||||
Type ExportType `json:"type,omitempty"`
|
||||
TokenReq bool `json:"token_req,omitempty"`
|
||||
Revocations RevocationList `json:"revocations,omitempty"`
|
||||
ResponseType ResponseType `json:"response_type,omitempty"`
|
||||
Latency *ServiceLatency `json:"service_latency,omitempty"`
|
||||
}
|
||||
|
||||
// IsService returns true if an export is for a service
|
||||
func (e *Export) IsService() bool {
|
||||
return e.Type == Service
|
||||
}
|
||||
|
||||
// IsStream returns true if an export is for a stream
|
||||
func (e *Export) IsStream() bool {
|
||||
return e.Type == Stream
|
||||
}
|
||||
|
||||
// IsSingleResponse returns true if an export has a single response
|
||||
// or no resopnse type is set, also checks that the type is service
|
||||
func (e *Export) IsSingleResponse() bool {
|
||||
return e.Type == Service && (e.ResponseType == ResponseTypeSingleton || e.ResponseType == "")
|
||||
}
|
||||
|
||||
// IsChunkedResponse returns true if an export has a chunked response
|
||||
func (e *Export) IsChunkedResponse() bool {
|
||||
return e.Type == Service && e.ResponseType == ResponseTypeChunked
|
||||
}
|
||||
|
||||
// IsStreamResponse returns true if an export has a chunked response
|
||||
func (e *Export) IsStreamResponse() bool {
|
||||
return e.Type == Service && e.ResponseType == ResponseTypeStream
|
||||
}
|
||||
|
||||
// Validate appends validation issues to the passed in results list
|
||||
func (e *Export) Validate(vr *ValidationResults) {
|
||||
if !e.IsService() && !e.IsStream() {
|
||||
vr.AddError("invalid export type: %q", e.Type)
|
||||
}
|
||||
if e.IsService() && !e.IsSingleResponse() && !e.IsChunkedResponse() && !e.IsStreamResponse() {
|
||||
vr.AddError("invalid response type for service: %q", e.ResponseType)
|
||||
}
|
||||
if e.IsStream() && e.ResponseType != "" {
|
||||
vr.AddError("invalid response type for stream: %q", e.ResponseType)
|
||||
}
|
||||
if e.Latency != nil {
|
||||
if !e.IsService() {
|
||||
vr.AddError("latency tracking only permitted for services")
|
||||
}
|
||||
e.Latency.Validate(vr)
|
||||
}
|
||||
e.Subject.Validate(vr)
|
||||
}
|
||||
|
||||
// Revoke enters a revocation by publickey using time.Now().
|
||||
func (e *Export) Revoke(pubKey string) {
|
||||
e.RevokeAt(pubKey, time.Now())
|
||||
}
|
||||
|
||||
// RevokeAt enters a revocation by publickey and timestamp into this export
|
||||
// If there is already a revocation for this public key that is newer, it is kept.
|
||||
func (e *Export) RevokeAt(pubKey string, timestamp time.Time) {
|
||||
if e.Revocations == nil {
|
||||
e.Revocations = RevocationList{}
|
||||
}
|
||||
|
||||
e.Revocations.Revoke(pubKey, timestamp)
|
||||
}
|
||||
|
||||
// ClearRevocation removes any revocation for the public key
|
||||
func (e *Export) ClearRevocation(pubKey string) {
|
||||
e.Revocations.ClearRevocation(pubKey)
|
||||
}
|
||||
|
||||
// IsRevokedAt checks if the public key is in the revoked list with a timestamp later than
|
||||
// the one passed in. Generally this method is called with time.Now() but other time's can
|
||||
// be used for testing.
|
||||
func (e *Export) IsRevokedAt(pubKey string, timestamp time.Time) bool {
|
||||
return e.Revocations.IsRevoked(pubKey, timestamp)
|
||||
}
|
||||
|
||||
// IsRevoked checks if the public key is in the revoked list with time.Now()
|
||||
func (e *Export) IsRevoked(pubKey string) bool {
|
||||
return e.Revocations.IsRevoked(pubKey, time.Now())
|
||||
}
|
||||
|
||||
// Exports is a slice of exports
|
||||
type Exports []*Export
|
||||
|
||||
// Add appends exports to the list
|
||||
func (e *Exports) Add(i ...*Export) {
|
||||
*e = append(*e, i...)
|
||||
}
|
||||
|
||||
func isContainedIn(kind ExportType, subjects []Subject, vr *ValidationResults) {
|
||||
m := make(map[string]string)
|
||||
for i, ns := range subjects {
|
||||
for j, s := range subjects {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
if ns.IsContainedIn(s) {
|
||||
str := string(s)
|
||||
_, ok := m[str]
|
||||
if !ok {
|
||||
m[str] = string(ns)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(m) != 0 {
|
||||
for k, v := range m {
|
||||
var vi ValidationIssue
|
||||
vi.Blocking = true
|
||||
vi.Description = fmt.Sprintf("%s export subject %q already exports %q", kind, k, v)
|
||||
vr.Add(&vi)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate calls validate on all of the exports
|
||||
func (e *Exports) Validate(vr *ValidationResults) error {
|
||||
var serviceSubjects []Subject
|
||||
var streamSubjects []Subject
|
||||
|
||||
for _, v := range *e {
|
||||
if v.IsService() {
|
||||
serviceSubjects = append(serviceSubjects, v.Subject)
|
||||
} else {
|
||||
streamSubjects = append(streamSubjects, v.Subject)
|
||||
}
|
||||
v.Validate(vr)
|
||||
}
|
||||
|
||||
isContainedIn(Service, serviceSubjects, vr)
|
||||
isContainedIn(Stream, streamSubjects, vr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasExportContainingSubject checks if the export list has an export with the provided subject
|
||||
func (e *Exports) HasExportContainingSubject(subject Subject) bool {
|
||||
for _, s := range *e {
|
||||
if subject.IsContainedIn(s.Subject) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (e Exports) Len() int {
|
||||
return len(e)
|
||||
}
|
||||
|
||||
func (e Exports) Swap(i, j int) {
|
||||
e[i], e[j] = e[j], e[i]
|
||||
}
|
||||
|
||||
func (e Exports) Less(i, j int) bool {
|
||||
return e[i].Subject < e[j].Subject
|
||||
}
|
73
vendor/github.com/nats-io/jwt/genericlaims.go
generated
vendored
Normal file
73
vendor/github.com/nats-io/jwt/genericlaims.go
generated
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2018 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import "github.com/nats-io/nkeys"
|
||||
|
||||
// GenericClaims can be used to read a JWT as a map for any non-generic fields
|
||||
type GenericClaims struct {
|
||||
ClaimsData
|
||||
Data map[string]interface{} `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewGenericClaims creates a map-based Claims
|
||||
func NewGenericClaims(subject string) *GenericClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := GenericClaims{}
|
||||
c.Subject = subject
|
||||
c.Data = make(map[string]interface{})
|
||||
return &c
|
||||
}
|
||||
|
||||
// DecodeGeneric takes a JWT string and decodes it into a ClaimsData and map
|
||||
func DecodeGeneric(token string) (*GenericClaims, error) {
|
||||
v := GenericClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
// Claims returns the standard part of the generic claim
|
||||
func (gc *GenericClaims) Claims() *ClaimsData {
|
||||
return &gc.ClaimsData
|
||||
}
|
||||
|
||||
// Payload returns the custom part of the claims data
|
||||
func (gc *GenericClaims) Payload() interface{} {
|
||||
return &gc.Data
|
||||
}
|
||||
|
||||
// Encode takes a generic claims and creates a JWT string
|
||||
func (gc *GenericClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
return gc.ClaimsData.Encode(pair, gc)
|
||||
}
|
||||
|
||||
// Validate checks the generic part of the claims data
|
||||
func (gc *GenericClaims) Validate(vr *ValidationResults) {
|
||||
gc.ClaimsData.Validate(vr)
|
||||
}
|
||||
|
||||
func (gc *GenericClaims) String() string {
|
||||
return gc.ClaimsData.String(gc)
|
||||
}
|
||||
|
||||
// ExpectedPrefixes returns the types allowed to encode a generic JWT, which is nil for all
|
||||
func (gc *GenericClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return nil
|
||||
}
|
3
vendor/github.com/nats-io/jwt/go.mod
generated
vendored
Normal file
3
vendor/github.com/nats-io/jwt/go.mod
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/nats-io/jwt
|
||||
|
||||
require github.com/nats-io/nkeys v0.1.3
|
9
vendor/github.com/nats-io/jwt/go.sum
generated
vendored
Normal file
9
vendor/github.com/nats-io/jwt/go.sum
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
github.com/nats-io/nkeys v0.1.3 h1:6JrEfig+HzTH85yxzhSVbjHRJv9cn0p6n3IngIcM5/k=
|
||||
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
71
vendor/github.com/nats-io/jwt/header.go
generated
vendored
Normal file
71
vendor/github.com/nats-io/jwt/header.go
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright 2018-2019 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Version is semantic version.
|
||||
Version = "0.3.2"
|
||||
|
||||
// TokenTypeJwt is the JWT token type supported JWT tokens
|
||||
// encoded and decoded by this library
|
||||
TokenTypeJwt = "jwt"
|
||||
|
||||
// AlgorithmNkey is the algorithm supported by JWT tokens
|
||||
// encoded and decoded by this library
|
||||
AlgorithmNkey = "ed25519"
|
||||
)
|
||||
|
||||
// Header is a JWT Jose Header
|
||||
type Header struct {
|
||||
Type string `json:"typ"`
|
||||
Algorithm string `json:"alg"`
|
||||
}
|
||||
|
||||
// Parses a header JWT token
|
||||
func parseHeaders(s string) (*Header, error) {
|
||||
h, err := decodeString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
header := Header{}
|
||||
if err := json.Unmarshal(h, &header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := header.Valid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &header, nil
|
||||
}
|
||||
|
||||
// Valid validates the Header. It returns nil if the Header is
|
||||
// a JWT header, and the algorithm used is the NKEY algorithm.
|
||||
func (h *Header) Valid() error {
|
||||
if TokenTypeJwt != strings.ToLower(h.Type) {
|
||||
return fmt.Errorf("not supported type %q", h.Type)
|
||||
}
|
||||
|
||||
if AlgorithmNkey != strings.ToLower(h.Algorithm) {
|
||||
return fmt.Errorf("unexpected %q algorithm", h.Algorithm)
|
||||
}
|
||||
return nil
|
||||
}
|
151
vendor/github.com/nats-io/jwt/imports.go
generated
vendored
Normal file
151
vendor/github.com/nats-io/jwt/imports.go
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2018-2019 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Import describes a mapping from another account into this one
|
||||
type Import struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
// Subject field in an import is always from the perspective of the
|
||||
// initial publisher - in the case of a stream it is the account owning
|
||||
// the stream (the exporter), and in the case of a service it is the
|
||||
// account making the request (the importer).
|
||||
Subject Subject `json:"subject,omitempty"`
|
||||
Account string `json:"account,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
// To field in an import is always from the perspective of the subscriber
|
||||
// in the case of a stream it is the client of the stream (the importer),
|
||||
// from the perspective of a service, it is the subscription waiting for
|
||||
// requests (the exporter). If the field is empty, it will default to the
|
||||
// value in the Subject field.
|
||||
To Subject `json:"to,omitempty"`
|
||||
Type ExportType `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// IsService returns true if the import is of type service
|
||||
func (i *Import) IsService() bool {
|
||||
return i.Type == Service
|
||||
}
|
||||
|
||||
// IsStream returns true if the import is of type stream
|
||||
func (i *Import) IsStream() bool {
|
||||
return i.Type == Stream
|
||||
}
|
||||
|
||||
// Validate checks if an import is valid for the wrapping account
|
||||
func (i *Import) Validate(actPubKey string, vr *ValidationResults) {
|
||||
if !i.IsService() && !i.IsStream() {
|
||||
vr.AddError("invalid import type: %q", i.Type)
|
||||
}
|
||||
|
||||
if i.Account == "" {
|
||||
vr.AddWarning("account to import from is not specified")
|
||||
}
|
||||
|
||||
i.Subject.Validate(vr)
|
||||
|
||||
if i.IsService() && i.Subject.HasWildCards() {
|
||||
vr.AddError("services cannot have wildcard subject: %q", i.Subject)
|
||||
}
|
||||
if i.IsStream() && i.To.HasWildCards() {
|
||||
vr.AddError("streams cannot have wildcard to subject: %q", i.Subject)
|
||||
}
|
||||
|
||||
var act *ActivationClaims
|
||||
|
||||
if i.Token != "" {
|
||||
// Check to see if its an embedded JWT or a URL.
|
||||
if url, err := url.Parse(i.Token); err == nil && url.Scheme != "" {
|
||||
c := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := c.Get(url.String())
|
||||
if err != nil {
|
||||
vr.AddWarning("import %s contains an unreachable token URL %q", i.Subject, i.Token)
|
||||
}
|
||||
|
||||
if resp != nil {
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
vr.AddWarning("import %s contains an unreadable token URL %q", i.Subject, i.Token)
|
||||
} else {
|
||||
act, err = DecodeActivationClaims(string(body))
|
||||
if err != nil {
|
||||
vr.AddWarning("import %s contains a url %q with an invalid activation token", i.Subject, i.Token)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
act, err = DecodeActivationClaims(i.Token)
|
||||
if err != nil {
|
||||
vr.AddWarning("import %q contains an invalid activation token", i.Subject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if act != nil {
|
||||
if act.Issuer != i.Account {
|
||||
vr.AddWarning("activation token doesn't match account for import %q", i.Subject)
|
||||
}
|
||||
|
||||
if act.ClaimsData.Subject != actPubKey {
|
||||
vr.AddWarning("activation token doesn't match account it is being included in, %q", i.Subject)
|
||||
}
|
||||
} else {
|
||||
vr.AddWarning("no activation provided for import %s", i.Subject)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Imports is a list of import structs
|
||||
type Imports []*Import
|
||||
|
||||
// Validate checks if an import is valid for the wrapping account
|
||||
func (i *Imports) Validate(acctPubKey string, vr *ValidationResults) {
|
||||
toSet := make(map[Subject]bool, len(*i))
|
||||
for _, v := range *i {
|
||||
if v.Type == Service {
|
||||
if _, ok := toSet[v.To]; ok {
|
||||
vr.AddError("Duplicate To subjects for %q", v.To)
|
||||
}
|
||||
toSet[v.To] = true
|
||||
}
|
||||
v.Validate(acctPubKey, vr)
|
||||
}
|
||||
}
|
||||
|
||||
// Add is a simple way to add imports
|
||||
func (i *Imports) Add(a ...*Import) {
|
||||
*i = append(*i, a...)
|
||||
}
|
||||
|
||||
func (i Imports) Len() int {
|
||||
return len(i)
|
||||
}
|
||||
|
||||
func (i Imports) Swap(j, k int) {
|
||||
i[j], i[k] = i[k], i[j]
|
||||
}
|
||||
|
||||
func (i Imports) Less(j, k int) bool {
|
||||
return i[j].Subject < i[k].Subject
|
||||
}
|
204
vendor/github.com/nats-io/jwt/operator_claims.go
generated
vendored
Normal file
204
vendor/github.com/nats-io/jwt/operator_claims.go
generated
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright 2018 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// Operator specific claims
|
||||
type Operator struct {
|
||||
// Slice of real identies (like websites) that can be used to identify the operator.
|
||||
Identities []Identity `json:"identity,omitempty"`
|
||||
// Slice of other operator NKeys that can be used to sign on behalf of the main
|
||||
// operator identity.
|
||||
SigningKeys StringList `json:"signing_keys,omitempty"`
|
||||
// AccountServerURL is a partial URL like "https://host.domain.org:<port>/jwt/v1"
|
||||
// tools will use the prefix and build queries by appending /accounts/<account_id>
|
||||
// or /operator to the path provided. Note this assumes that the account server
|
||||
// can handle requests in a nats-account-server compatible way. See
|
||||
// https://github.com/nats-io/nats-account-server.
|
||||
AccountServerURL string `json:"account_server_url,omitempty"`
|
||||
// A list of NATS urls (tls://host:port) where tools can connect to the server
|
||||
// using proper credentials.
|
||||
OperatorServiceURLs StringList `json:"operator_service_urls,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the validity of the operators contents
|
||||
func (o *Operator) Validate(vr *ValidationResults) {
|
||||
if err := o.validateAccountServerURL(); err != nil {
|
||||
vr.AddError(err.Error())
|
||||
}
|
||||
|
||||
for _, v := range o.validateOperatorServiceURLs() {
|
||||
if v != nil {
|
||||
vr.AddError(v.Error())
|
||||
}
|
||||
}
|
||||
|
||||
for _, i := range o.Identities {
|
||||
i.Validate(vr)
|
||||
}
|
||||
|
||||
for _, k := range o.SigningKeys {
|
||||
if !nkeys.IsValidPublicOperatorKey(k) {
|
||||
vr.AddError("%s is not an operator public key", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Operator) validateAccountServerURL() error {
|
||||
if o.AccountServerURL != "" {
|
||||
// We don't care what kind of URL it is so long as it parses
|
||||
// and has a protocol. The account server may impose additional
|
||||
// constraints on the type of URLs that it is able to notify to
|
||||
u, err := url.Parse(o.AccountServerURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing account server url: %v", err)
|
||||
}
|
||||
if u.Scheme == "" {
|
||||
return fmt.Errorf("account server url %q requires a protocol", o.AccountServerURL)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateOperatorServiceURL returns an error if the URL is not a valid NATS or TLS url.
|
||||
func ValidateOperatorServiceURL(v string) error {
|
||||
// should be possible for the service url to not be expressed
|
||||
if v == "" {
|
||||
return nil
|
||||
}
|
||||
u, err := url.Parse(v)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing operator service url %q: %v", v, err)
|
||||
}
|
||||
|
||||
if u.User != nil {
|
||||
return fmt.Errorf("operator service url %q - credentials are not supported", v)
|
||||
}
|
||||
|
||||
if u.Path != "" {
|
||||
return fmt.Errorf("operator service url %q - paths are not supported", v)
|
||||
}
|
||||
|
||||
lcs := strings.ToLower(u.Scheme)
|
||||
switch lcs {
|
||||
case "nats":
|
||||
return nil
|
||||
case "tls":
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("operator service url %q - protocol not supported (only 'nats' or 'tls' only)", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Operator) validateOperatorServiceURLs() []error {
|
||||
var errors []error
|
||||
for _, v := range o.OperatorServiceURLs {
|
||||
if v != "" {
|
||||
if err := ValidateOperatorServiceURL(v); err != nil {
|
||||
errors = append(errors, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors
|
||||
}
|
||||
|
||||
// OperatorClaims define the data for an operator JWT
|
||||
type OperatorClaims struct {
|
||||
ClaimsData
|
||||
Operator `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewOperatorClaims creates a new operator claim with the specified subject, which should be an operator public key
|
||||
func NewOperatorClaims(subject string) *OperatorClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &OperatorClaims{}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// DidSign checks the claims against the operator's public key and its signing keys
|
||||
func (oc *OperatorClaims) DidSign(op Claims) bool {
|
||||
if op == nil {
|
||||
return false
|
||||
}
|
||||
issuer := op.Claims().Issuer
|
||||
if issuer == oc.Subject {
|
||||
return true
|
||||
}
|
||||
return oc.SigningKeys.Contains(issuer)
|
||||
}
|
||||
|
||||
// Deprecated: AddSigningKey, use claim.SigningKeys.Add()
|
||||
func (oc *OperatorClaims) AddSigningKey(pk string) {
|
||||
oc.SigningKeys.Add(pk)
|
||||
}
|
||||
|
||||
// Encode the claims into a JWT string
|
||||
func (oc *OperatorClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicOperatorKey(oc.Subject) {
|
||||
return "", errors.New("expected subject to be an operator public key")
|
||||
}
|
||||
err := oc.validateAccountServerURL()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
oc.ClaimsData.Type = OperatorClaim
|
||||
return oc.ClaimsData.Encode(pair, oc)
|
||||
}
|
||||
|
||||
// DecodeOperatorClaims tries to create an operator claims from a JWt string
|
||||
func DecodeOperatorClaims(token string) (*OperatorClaims, error) {
|
||||
v := OperatorClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (oc *OperatorClaims) String() string {
|
||||
return oc.ClaimsData.String(oc)
|
||||
}
|
||||
|
||||
// Payload returns the operator specific data for an operator JWT
|
||||
func (oc *OperatorClaims) Payload() interface{} {
|
||||
return &oc.Operator
|
||||
}
|
||||
|
||||
// Validate the contents of the claims
|
||||
func (oc *OperatorClaims) Validate(vr *ValidationResults) {
|
||||
oc.ClaimsData.Validate(vr)
|
||||
oc.Operator.Validate(vr)
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the nkey types that can sign operator claims, operator
|
||||
func (oc *OperatorClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteOperator}
|
||||
}
|
||||
|
||||
// Claims returns the generic claims data
|
||||
func (oc *OperatorClaims) Claims() *ClaimsData {
|
||||
return &oc.ClaimsData
|
||||
}
|
32
vendor/github.com/nats-io/jwt/revocation_list.go
generated
vendored
Normal file
32
vendor/github.com/nats-io/jwt/revocation_list.go
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RevocationList is used to store a mapping of public keys to unix timestamps
|
||||
type RevocationList map[string]int64
|
||||
|
||||
// Revoke enters a revocation by publickey and timestamp into this export
|
||||
// If there is already a revocation for this public key that is newer, it is kept.
|
||||
func (r RevocationList) Revoke(pubKey string, timestamp time.Time) {
|
||||
newTS := timestamp.Unix()
|
||||
if ts, ok := r[pubKey]; ok && ts > newTS {
|
||||
return
|
||||
}
|
||||
|
||||
r[pubKey] = newTS
|
||||
}
|
||||
|
||||
// ClearRevocation removes any revocation for the public key
|
||||
func (r RevocationList) ClearRevocation(pubKey string) {
|
||||
delete(r, pubKey)
|
||||
}
|
||||
|
||||
// IsRevoked checks if the public key is in the revoked list with a timestamp later than
|
||||
// the one passed in. Generally this method is called with time.Now() but other time's can
|
||||
// be used for testing.
|
||||
func (r RevocationList) IsRevoked(pubKey string, timestamp time.Time) bool {
|
||||
ts, ok := r[pubKey]
|
||||
return ok && ts > timestamp.Unix()
|
||||
}
|
94
vendor/github.com/nats-io/jwt/server_claims.go
generated
vendored
Normal file
94
vendor/github.com/nats-io/jwt/server_claims.go
generated
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2018 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// Server defines the custom part of a server jwt
|
||||
type Server struct {
|
||||
Permissions
|
||||
Cluster string `json:"cluster,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the cluster and permissions for a server JWT
|
||||
func (s *Server) Validate(vr *ValidationResults) {
|
||||
if s.Cluster == "" {
|
||||
vr.AddError("servers can't contain an empty cluster")
|
||||
}
|
||||
}
|
||||
|
||||
// ServerClaims defines the data in a server JWT
|
||||
type ServerClaims struct {
|
||||
ClaimsData
|
||||
Server `json:"nats,omitempty"`
|
||||
}
|
||||
|
||||
// NewServerClaims creates a new server JWT with the specified subject/public key
|
||||
func NewServerClaims(subject string) *ServerClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &ServerClaims{}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// Encode tries to turn the server claims into a JWT string
|
||||
func (s *ServerClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicServerKey(s.Subject) {
|
||||
return "", errors.New("expected subject to be a server public key")
|
||||
}
|
||||
s.ClaimsData.Type = ServerClaim
|
||||
return s.ClaimsData.Encode(pair, s)
|
||||
}
|
||||
|
||||
// DecodeServerClaims tries to parse server claims from a JWT string
|
||||
func DecodeServerClaims(token string) (*ServerClaims, error) {
|
||||
v := ServerClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (s *ServerClaims) String() string {
|
||||
return s.ClaimsData.String(s)
|
||||
}
|
||||
|
||||
// Payload returns the server specific data
|
||||
func (s *ServerClaims) Payload() interface{} {
|
||||
return &s.Server
|
||||
}
|
||||
|
||||
// Validate checks the generic and server data in the server claims
|
||||
func (s *ServerClaims) Validate(vr *ValidationResults) {
|
||||
s.ClaimsData.Validate(vr)
|
||||
s.Server.Validate(vr)
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can encode a server JWT, operator or cluster
|
||||
func (s *ServerClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteOperator, nkeys.PrefixByteCluster}
|
||||
}
|
||||
|
||||
// Claims returns the generic data
|
||||
func (s *ServerClaims) Claims() *ClaimsData {
|
||||
return &s.ClaimsData
|
||||
}
|
334
vendor/github.com/nats-io/jwt/types.go
generated
vendored
Normal file
334
vendor/github.com/nats-io/jwt/types.go
generated
vendored
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright 2018-2019 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ExportType defines the type of import/export.
|
||||
type ExportType int
|
||||
|
||||
const (
|
||||
// Unknown is used if we don't know the type
|
||||
Unknown ExportType = iota
|
||||
// Stream defines the type field value for a stream "stream"
|
||||
Stream
|
||||
// Service defines the type field value for a service "service"
|
||||
Service
|
||||
)
|
||||
|
||||
func (t ExportType) String() string {
|
||||
switch t {
|
||||
case Stream:
|
||||
return "stream"
|
||||
case Service:
|
||||
return "service"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the enum as a quoted json string
|
||||
func (t *ExportType) MarshalJSON() ([]byte, error) {
|
||||
switch *t {
|
||||
case Stream:
|
||||
return []byte("\"stream\""), nil
|
||||
case Service:
|
||||
return []byte("\"service\""), nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown export type")
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmashals a quoted json string to the enum value
|
||||
func (t *ExportType) UnmarshalJSON(b []byte) error {
|
||||
var j string
|
||||
err := json.Unmarshal(b, &j)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch j {
|
||||
case "stream":
|
||||
*t = Stream
|
||||
return nil
|
||||
case "service":
|
||||
*t = Service
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown export type")
|
||||
}
|
||||
|
||||
// Subject is a string that represents a NATS subject
|
||||
type Subject string
|
||||
|
||||
// Validate checks that a subject string is valid, ie not empty and without spaces
|
||||
func (s Subject) Validate(vr *ValidationResults) {
|
||||
v := string(s)
|
||||
if v == "" {
|
||||
vr.AddError("subject cannot be empty")
|
||||
}
|
||||
if strings.Contains(v, " ") {
|
||||
vr.AddError("subject %q cannot have spaces", v)
|
||||
}
|
||||
}
|
||||
|
||||
// HasWildCards is used to check if a subject contains a > or *
|
||||
func (s Subject) HasWildCards() bool {
|
||||
v := string(s)
|
||||
return strings.HasSuffix(v, ".>") ||
|
||||
strings.Contains(v, ".*.") ||
|
||||
strings.HasSuffix(v, ".*") ||
|
||||
strings.HasPrefix(v, "*.") ||
|
||||
v == "*" ||
|
||||
v == ">"
|
||||
}
|
||||
|
||||
// IsContainedIn does a simple test to see if the subject is contained in another subject
|
||||
func (s Subject) IsContainedIn(other Subject) bool {
|
||||
otherArray := strings.Split(string(other), ".")
|
||||
myArray := strings.Split(string(s), ".")
|
||||
|
||||
if len(myArray) > len(otherArray) && otherArray[len(otherArray)-1] != ">" {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(myArray) < len(otherArray) {
|
||||
return false
|
||||
}
|
||||
|
||||
for ind, tok := range otherArray {
|
||||
myTok := myArray[ind]
|
||||
|
||||
if ind == len(otherArray)-1 && tok == ">" {
|
||||
return true
|
||||
}
|
||||
|
||||
if tok != myTok && tok != "*" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// NamedSubject is the combination of a subject and a name for it
|
||||
type NamedSubject struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Subject Subject `json:"subject,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the subject
|
||||
func (ns *NamedSubject) Validate(vr *ValidationResults) {
|
||||
ns.Subject.Validate(vr)
|
||||
}
|
||||
|
||||
// TimeRange is used to represent a start and end time
|
||||
type TimeRange struct {
|
||||
Start string `json:"start,omitempty"`
|
||||
End string `json:"end,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the values in a time range struct
|
||||
func (tr *TimeRange) Validate(vr *ValidationResults) {
|
||||
format := "15:04:05"
|
||||
|
||||
if tr.Start == "" {
|
||||
vr.AddError("time ranges start must contain a start")
|
||||
} else {
|
||||
_, err := time.Parse(format, tr.Start)
|
||||
if err != nil {
|
||||
vr.AddError("start in time range is invalid %q", tr.Start)
|
||||
}
|
||||
}
|
||||
|
||||
if tr.End == "" {
|
||||
vr.AddError("time ranges end must contain an end")
|
||||
} else {
|
||||
_, err := time.Parse(format, tr.End)
|
||||
if err != nil {
|
||||
vr.AddError("end in time range is invalid %q", tr.End)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Limits are used to control acccess for users and importing accounts
|
||||
// Src is a comma separated list of CIDR specifications
|
||||
type Limits struct {
|
||||
Max int64 `json:"max,omitempty"`
|
||||
Payload int64 `json:"payload,omitempty"`
|
||||
Src string `json:"src,omitempty"`
|
||||
Times []TimeRange `json:"times,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the values in a limit struct
|
||||
func (l *Limits) Validate(vr *ValidationResults) {
|
||||
if l.Max < 0 {
|
||||
vr.AddError("limits cannot contain a negative maximum, %d", l.Max)
|
||||
}
|
||||
if l.Payload < 0 {
|
||||
vr.AddError("limits cannot contain a negative payload, %d", l.Payload)
|
||||
}
|
||||
|
||||
if l.Src != "" {
|
||||
elements := strings.Split(l.Src, ",")
|
||||
|
||||
for _, cidr := range elements {
|
||||
cidr = strings.TrimSpace(cidr)
|
||||
_, ipNet, err := net.ParseCIDR(cidr)
|
||||
if err != nil || ipNet == nil {
|
||||
vr.AddError("invalid cidr %q in user src limits", cidr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if l.Times != nil && len(l.Times) > 0 {
|
||||
for _, t := range l.Times {
|
||||
t.Validate(vr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Permission defines allow/deny subjects
|
||||
type Permission struct {
|
||||
Allow StringList `json:"allow,omitempty"`
|
||||
Deny StringList `json:"deny,omitempty"`
|
||||
}
|
||||
|
||||
// Validate the allow, deny elements of a permission
|
||||
func (p *Permission) Validate(vr *ValidationResults) {
|
||||
for _, subj := range p.Allow {
|
||||
Subject(subj).Validate(vr)
|
||||
}
|
||||
for _, subj := range p.Deny {
|
||||
Subject(subj).Validate(vr)
|
||||
}
|
||||
}
|
||||
|
||||
// ResponsePermission can be used to allow responses to any reply subject
|
||||
// that is received on a valid subscription.
|
||||
type ResponsePermission struct {
|
||||
MaxMsgs int `json:"max"`
|
||||
Expires time.Duration `json:"ttl"`
|
||||
}
|
||||
|
||||
// Validate the response permission.
|
||||
func (p *ResponsePermission) Validate(vr *ValidationResults) {
|
||||
// Any values can be valid for now.
|
||||
}
|
||||
|
||||
// Permissions are used to restrict subject access, either on a user or for everyone on a server by default
|
||||
type Permissions struct {
|
||||
Pub Permission `json:"pub,omitempty"`
|
||||
Sub Permission `json:"sub,omitempty"`
|
||||
Resp *ResponsePermission `json:"resp,omitempty"`
|
||||
}
|
||||
|
||||
// Validate the pub and sub fields in the permissions list
|
||||
func (p *Permissions) Validate(vr *ValidationResults) {
|
||||
p.Pub.Validate(vr)
|
||||
p.Sub.Validate(vr)
|
||||
if p.Resp != nil {
|
||||
p.Resp.Validate(vr)
|
||||
}
|
||||
}
|
||||
|
||||
// StringList is a wrapper for an array of strings
|
||||
type StringList []string
|
||||
|
||||
// Contains returns true if the list contains the string
|
||||
func (u *StringList) Contains(p string) bool {
|
||||
for _, t := range *u {
|
||||
if t == p {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Add appends 1 or more strings to a list
|
||||
func (u *StringList) Add(p ...string) {
|
||||
for _, v := range p {
|
||||
if !u.Contains(v) && v != "" {
|
||||
*u = append(*u, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes 1 or more strings from a list
|
||||
func (u *StringList) Remove(p ...string) {
|
||||
for _, v := range p {
|
||||
for i, t := range *u {
|
||||
if t == v {
|
||||
a := *u
|
||||
*u = append(a[:i], a[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TagList is a unique array of lower case strings
|
||||
// All tag list methods lower case the strings in the arguments
|
||||
type TagList []string
|
||||
|
||||
// Contains returns true if the list contains the tags
|
||||
func (u *TagList) Contains(p string) bool {
|
||||
p = strings.ToLower(p)
|
||||
for _, t := range *u {
|
||||
if t == p {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Add appends 1 or more tags to a list
|
||||
func (u *TagList) Add(p ...string) {
|
||||
for _, v := range p {
|
||||
v = strings.ToLower(v)
|
||||
if !u.Contains(v) && v != "" {
|
||||
*u = append(*u, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes 1 or more tags from a list
|
||||
func (u *TagList) Remove(p ...string) {
|
||||
for _, v := range p {
|
||||
v = strings.ToLower(v)
|
||||
for i, t := range *u {
|
||||
if t == v {
|
||||
a := *u
|
||||
*u = append(a[:i], a[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Identity is used to associate an account or operator with a real entity
|
||||
type Identity struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Proof string `json:"proof,omitempty"`
|
||||
}
|
||||
|
||||
// Validate checks the values in an Identity
|
||||
func (u *Identity) Validate(vr *ValidationResults) {
|
||||
//Fixme identity validation
|
||||
}
|
99
vendor/github.com/nats-io/jwt/user_claims.go
generated
vendored
Normal file
99
vendor/github.com/nats-io/jwt/user_claims.go
generated
vendored
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2018-2019 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nats-io/nkeys"
|
||||
)
|
||||
|
||||
// User defines the user specific data in a user JWT
|
||||
type User struct {
|
||||
Permissions
|
||||
Limits
|
||||
}
|
||||
|
||||
// Validate checks the permissions and limits in a User jwt
|
||||
func (u *User) Validate(vr *ValidationResults) {
|
||||
u.Permissions.Validate(vr)
|
||||
u.Limits.Validate(vr)
|
||||
}
|
||||
|
||||
// UserClaims defines a user JWT
|
||||
type UserClaims struct {
|
||||
ClaimsData
|
||||
User `json:"nats,omitempty"`
|
||||
// IssuerAccount stores the public key for the account the issuer represents.
|
||||
// When set, the claim was issued by a signing key.
|
||||
IssuerAccount string `json:"issuer_account,omitempty"`
|
||||
}
|
||||
|
||||
// NewUserClaims creates a user JWT with the specific subject/public key
|
||||
func NewUserClaims(subject string) *UserClaims {
|
||||
if subject == "" {
|
||||
return nil
|
||||
}
|
||||
c := &UserClaims{}
|
||||
c.Subject = subject
|
||||
return c
|
||||
}
|
||||
|
||||
// Encode tries to turn the user claims into a JWT string
|
||||
func (u *UserClaims) Encode(pair nkeys.KeyPair) (string, error) {
|
||||
if !nkeys.IsValidPublicUserKey(u.Subject) {
|
||||
return "", errors.New("expected subject to be user public key")
|
||||
}
|
||||
u.ClaimsData.Type = UserClaim
|
||||
return u.ClaimsData.Encode(pair, u)
|
||||
}
|
||||
|
||||
// DecodeUserClaims tries to parse a user claims from a JWT string
|
||||
func DecodeUserClaims(token string) (*UserClaims, error) {
|
||||
v := UserClaims{}
|
||||
if err := Decode(token, &v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
// Validate checks the generic and specific parts of the user jwt
|
||||
func (u *UserClaims) Validate(vr *ValidationResults) {
|
||||
u.ClaimsData.Validate(vr)
|
||||
u.User.Validate(vr)
|
||||
if u.IssuerAccount != "" && !nkeys.IsValidPublicAccountKey(u.IssuerAccount) {
|
||||
vr.AddError("account_id is not an account public key")
|
||||
}
|
||||
}
|
||||
|
||||
// ExpectedPrefixes defines the types that can encode a user JWT, account
|
||||
func (u *UserClaims) ExpectedPrefixes() []nkeys.PrefixByte {
|
||||
return []nkeys.PrefixByte{nkeys.PrefixByteAccount}
|
||||
}
|
||||
|
||||
// Claims returns the generic data from a user jwt
|
||||
func (u *UserClaims) Claims() *ClaimsData {
|
||||
return &u.ClaimsData
|
||||
}
|
||||
|
||||
// Payload returns the user specific data from a user JWT
|
||||
func (u *UserClaims) Payload() interface{} {
|
||||
return &u.User
|
||||
}
|
||||
|
||||
func (u *UserClaims) String() string {
|
||||
return u.ClaimsData.String(u)
|
||||
}
|
107
vendor/github.com/nats-io/jwt/validation.go
generated
vendored
Normal file
107
vendor/github.com/nats-io/jwt/validation.go
generated
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2018 The NATS Authors
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ValidationIssue represents an issue during JWT validation, it may or may not be a blocking error
|
||||
type ValidationIssue struct {
|
||||
Description string
|
||||
Blocking bool
|
||||
TimeCheck bool
|
||||
}
|
||||
|
||||
func (ve *ValidationIssue) Error() string {
|
||||
return ve.Description
|
||||
}
|
||||
|
||||
// ValidationResults is a list of ValidationIssue pointers
|
||||
type ValidationResults struct {
|
||||
Issues []*ValidationIssue
|
||||
}
|
||||
|
||||
// CreateValidationResults creates an empty list of validation issues
|
||||
func CreateValidationResults() *ValidationResults {
|
||||
issues := []*ValidationIssue{}
|
||||
return &ValidationResults{
|
||||
Issues: issues,
|
||||
}
|
||||
}
|
||||
|
||||
//Add appends an issue to the list
|
||||
func (v *ValidationResults) Add(vi *ValidationIssue) {
|
||||
v.Issues = append(v.Issues, vi)
|
||||
}
|
||||
|
||||
// AddError creates a new validation error and adds it to the list
|
||||
func (v *ValidationResults) AddError(format string, args ...interface{}) {
|
||||
v.Add(&ValidationIssue{
|
||||
Description: fmt.Sprintf(format, args...),
|
||||
Blocking: true,
|
||||
TimeCheck: false,
|
||||
})
|
||||
}
|
||||
|
||||
// AddTimeCheck creates a new validation issue related to a time check and adds it to the list
|
||||
func (v *ValidationResults) AddTimeCheck(format string, args ...interface{}) {
|
||||
v.Add(&ValidationIssue{
|
||||
Description: fmt.Sprintf(format, args...),
|
||||
Blocking: false,
|
||||
TimeCheck: true,
|
||||
})
|
||||
}
|
||||
|
||||
// AddWarning creates a new validation warning and adds it to the list
|
||||
func (v *ValidationResults) AddWarning(format string, args ...interface{}) {
|
||||
v.Add(&ValidationIssue{
|
||||
Description: fmt.Sprintf(format, args...),
|
||||
Blocking: false,
|
||||
TimeCheck: false,
|
||||
})
|
||||
}
|
||||
|
||||
// IsBlocking returns true if the list contains a blocking error
|
||||
func (v *ValidationResults) IsBlocking(includeTimeChecks bool) bool {
|
||||
for _, i := range v.Issues {
|
||||
if i.Blocking {
|
||||
return true
|
||||
}
|
||||
|
||||
if includeTimeChecks && i.TimeCheck {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsEmpty returns true if the list is empty
|
||||
func (v *ValidationResults) IsEmpty() bool {
|
||||
return len(v.Issues) == 0
|
||||
}
|
||||
|
||||
// Errors returns only blocking issues as errors
|
||||
func (v *ValidationResults) Errors() []error {
|
||||
var errs []error
|
||||
for _, v := range v.Issues {
|
||||
if v.Blocking {
|
||||
errs = append(errs, errors.New(v.Description))
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
@ -37,3 +37,6 @@ _testmain.go
|
||||
.settings/
|
||||
|
||||
# bin
|
||||
|
||||
# Goland
|
||||
.idea
|
23
vendor/github.com/nats-io/nats.go/.travis.yml
generated
vendored
Normal file
23
vendor/github.com/nats-io/nats.go/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.11.x
|
||||
env:
|
||||
- GO111MODULE=off
|
||||
go_import_path: github.com/nats-io/nats.go
|
||||
install:
|
||||
- go get -t ./...
|
||||
- go get github.com/nats-io/nats-server
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get github.com/wadey/gocovmerge
|
||||
- go get -u honnef.co/go/tools/cmd/staticcheck
|
||||
- go get -u github.com/client9/misspell/cmd/misspell
|
||||
before_script:
|
||||
- $(exit $(go fmt ./... | wc -l))
|
||||
- go vet ./...
|
||||
- find . -type f -name "*.go" | xargs misspell -error -locale US
|
||||
- staticcheck ./...
|
||||
script:
|
||||
- go test -i -race ./...
|
||||
- if [[ "$TRAVIS_GO_VERSION" =~ 1.12 ]]; then ./scripts/cov.sh TRAVIS; else go test -race -v -p=1 ./... --failfast; fi
|
201
vendor/github.com/nats-io/nats.go/LICENSE
generated
vendored
Normal file
201
vendor/github.com/nats-io/nats.go/LICENSE
generated
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
@ -3,21 +3,36 @@ A [Go](http://golang.org) client for the [NATS messaging system](https://nats.io
|
||||
|
||||
[](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fnats-io%2Fgo-nats?ref=badge_shield)
|
||||
[](https://goreportcard.com/report/github.com/nats-io/go-nats) [](http://travis-ci.org/nats-io/go-nats) [](http://godoc.org/github.com/nats-io/go-nats) [](https://coveralls.io/r/nats-io/go-nats?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/nats-io/nats.go) [](http://travis-ci.org/nats-io/nats.go) [](http://godoc.org/github.com/nats-io/nats.go) [](https://coveralls.io/r/nats-io/nats.go?branch=master)
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Go client
|
||||
go get github.com/nats-io/go-nats
|
||||
go get github.com/nats-io/nats.go/
|
||||
|
||||
# Server
|
||||
go get github.com/nats-io/gnatsd
|
||||
go get github.com/nats-io/nats-server
|
||||
```
|
||||
|
||||
When using or transitioning to Go modules support:
|
||||
|
||||
```bash
|
||||
# Go client latest or explicit version
|
||||
go get github.com/nats-io/nats.go/@latest
|
||||
go get github.com/nats-io/nats.go/@v1.9.1
|
||||
|
||||
# For latest NATS Server, add /v2 at the end
|
||||
go get github.com/nats-io/nats-server/v2
|
||||
|
||||
# NATS Server v1 is installed otherwise
|
||||
# go get github.com/nats-io/nats-server
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
```go
|
||||
import nats "github.com/nats-io/nats.go"
|
||||
|
||||
// Connect to a server
|
||||
nc, _ := nats.Connect(nats.DefaultURL)
|
||||
@ -30,6 +45,11 @@ nc.Subscribe("foo", func(m *nats.Msg) {
|
||||
fmt.Printf("Received a message: %s\n", string(m.Data))
|
||||
})
|
||||
|
||||
// Responding to a request message
|
||||
nc.Subscribe("request", func(m *nats.Msg) {
|
||||
m.Respond([]byte("answer is 42"))
|
||||
})
|
||||
|
||||
// Simple Sync Subscriber
|
||||
sub, err := nc.SubscribeSync("foo")
|
||||
m, err := sub.NextMsg(timeout)
|
||||
@ -49,7 +69,7 @@ sub.Drain()
|
||||
msg, err := nc.Request("help", []byte("help me"), 10*time.Millisecond)
|
||||
|
||||
// Replies
|
||||
nc.Subscribe("help", func(m *Msg) {
|
||||
nc.Subscribe("help", func(m *nats.Msg) {
|
||||
nc.Publish(m.Reply, []byte("I can help!"))
|
||||
})
|
||||
|
||||
@ -96,12 +116,12 @@ c.Publish("hello", me)
|
||||
|
||||
// Unsubscribe
|
||||
sub, err := c.Subscribe("foo", nil)
|
||||
...
|
||||
// ...
|
||||
sub.Unsubscribe()
|
||||
|
||||
// Requests
|
||||
var response string
|
||||
err := c.Request("help", "help me", &response, 10*time.Millisecond)
|
||||
err = c.Request("help", "help me", &response, 10*time.Millisecond)
|
||||
if err != nil {
|
||||
fmt.Printf("Request failed: %v\n", err)
|
||||
}
|
||||
@ -115,6 +135,48 @@ c.Subscribe("help", func(subj, reply string, msg string) {
|
||||
c.Close();
|
||||
```
|
||||
|
||||
## New Authentication (Nkeys and User Credentials)
|
||||
This requires server with version >= 2.0.0
|
||||
|
||||
NATS servers have a new security and authentication mechanism to authenticate with user credentials and Nkeys.
|
||||
The simplest form is to use the helper method UserCredentials(credsFilepath).
|
||||
```go
|
||||
nc, err := nats.Connect(url, nats.UserCredentials("user.creds"))
|
||||
```
|
||||
|
||||
The helper methods creates two callback handlers to present the user JWT and sign the nonce challenge from the server.
|
||||
The core client library never has direct access to your private key and simply performs the callback for signing the server challenge.
|
||||
The helper will load and wipe and erase memory it uses for each connect or reconnect.
|
||||
|
||||
The helper also can take two entries, one for the JWT and one for the NKey seed file.
|
||||
```go
|
||||
nc, err := nats.Connect(url, nats.UserCredentials("user.jwt", "user.nk"))
|
||||
```
|
||||
|
||||
You can also set the callback handlers directly and manage challenge signing directly.
|
||||
```go
|
||||
nc, err := nats.Connect(url, nats.UserJWT(jwtCB, sigCB))
|
||||
```
|
||||
|
||||
Bare Nkeys are also supported. The nkey seed should be in a read only file, e.g. seed.txt
|
||||
```bash
|
||||
> cat seed.txt
|
||||
# This is my seed nkey!
|
||||
SUAGMJH5XLGZKQQWAWKRZJIGMOU4HPFUYLXJMXOO5NLFEO2OOQJ5LPRDPM
|
||||
```
|
||||
|
||||
This is a helper function which will load and decode and do the proper signing for the server nonce.
|
||||
It will clear memory in between invocations.
|
||||
You can choose to use the low level option and provide the public key and a signature callback on your own.
|
||||
|
||||
```go
|
||||
opt, err := nats.NkeyOptionFromSeed("seed.txt")
|
||||
nc, err := nats.Connect(serverUrl, opt)
|
||||
|
||||
// Direct
|
||||
nc, err := nats.Connect(serverUrl, nats.Nkey(pubNkey, sigCB))
|
||||
```
|
||||
|
||||
## TLS
|
||||
|
||||
```go
|
||||
@ -268,10 +330,10 @@ nc, err = nats.Connect(servers, nats.DontRandomize())
|
||||
|
||||
// Setup callbacks to be notified on disconnects, reconnects and connection closed.
|
||||
nc, err = nats.Connect(servers,
|
||||
nats.DisconnectHandler(func(nc *nats.Conn) {
|
||||
fmt.Printf("Got disconnected!\n")
|
||||
nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
|
||||
fmt.Printf("Got disconnected! Reason: %q\n", err)
|
||||
}),
|
||||
nats.ReconnectHandler(func(_ *nats.Conn) {
|
||||
nats.ReconnectHandler(func(nc *nats.Conn) {
|
||||
fmt.Printf("Got reconnected to %v!\n", nc.ConnectedUrl())
|
||||
}),
|
||||
nats.ClosedHandler(func(nc *nats.Conn) {
|
||||
@ -296,9 +358,9 @@ nc, err = nats.Connect("nats://localhost:4222",
|
||||
nats.Token("S3cretT0ken"))
|
||||
|
||||
// Note that if credentials are specified in the initial URLs, they take
|
||||
// precedence on the credentials specfied through the options.
|
||||
// precedence on the credentials specified through the options.
|
||||
// For instance, in the connect call below, the client library will use
|
||||
// the user "my" and password "pwd" to connect to locahost:4222, however,
|
||||
// the user "my" and password "pwd" to connect to localhost:4222, however,
|
||||
// it will use username "foo" and password "bar" when (re)connecting to
|
||||
// a different server URL that it got as part of the auto-discovery.
|
||||
nc, err = nats.Connect("nats://my:pwd@localhost:4222", nats.UserInfo("foo", "bar"))
|
@ -18,7 +18,6 @@ package nats
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
@ -44,31 +43,7 @@ func (nc *Conn) RequestWithContext(ctx context.Context, subj string, data []byte
|
||||
return nc.oldRequestWithContext(ctx, subj, data)
|
||||
}
|
||||
|
||||
// Do setup for the new style.
|
||||
if nc.respMap == nil {
|
||||
// _INBOX wildcard
|
||||
nc.respSub = fmt.Sprintf("%s.*", NewInbox())
|
||||
nc.respMap = make(map[string]chan *Msg)
|
||||
}
|
||||
// Create literal Inbox and map to a chan msg.
|
||||
mch := make(chan *Msg, RequestChanLen)
|
||||
respInbox := nc.newRespInbox()
|
||||
token := respToken(respInbox)
|
||||
nc.respMap[token] = mch
|
||||
createSub := nc.respMux == nil
|
||||
ginbox := nc.respSub
|
||||
nc.mu.Unlock()
|
||||
|
||||
if createSub {
|
||||
// Make sure scoped subscription is setup only once.
|
||||
var err error
|
||||
nc.respSetup.Do(func() { err = nc.createRespMux(ginbox) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err := nc.PublishRequest(subj, respInbox, data)
|
||||
mch, token, err := nc.createNewRequestAndSend(subj, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -96,7 +71,7 @@ func (nc *Conn) oldRequestWithContext(ctx context.Context, subj string, data []b
|
||||
inbox := NewInbox()
|
||||
ch := make(chan *Msg, RequestChanLen)
|
||||
|
||||
s, err := nc.subscribe(inbox, _EMPTY_, nil, ch)
|
||||
s, err := nc.subscribe(inbox, _EMPTY_, nil, ch, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -132,19 +107,33 @@ func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// snapshot
|
||||
mch := s.mch
|
||||
s.mu.Unlock()
|
||||
|
||||
var ok bool
|
||||
var msg *Msg
|
||||
|
||||
// If something is available right away, let's optimize that case.
|
||||
select {
|
||||
case msg, ok = <-mch:
|
||||
if !ok {
|
||||
return nil, ErrConnectionClosed
|
||||
return nil, s.getNextMsgErr()
|
||||
}
|
||||
err := s.processNextMsgDelivered(msg)
|
||||
if err != nil {
|
||||
if err := s.processNextMsgDelivered(msg); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return msg, nil
|
||||
}
|
||||
default:
|
||||
}
|
||||
|
||||
select {
|
||||
case msg, ok = <-mch:
|
||||
if !ok {
|
||||
return nil, s.getNextMsgErr()
|
||||
}
|
||||
if err := s.processNextMsgDelivered(msg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case <-ctx.Done():
|
||||
@ -154,6 +143,52 @@ func (s *Subscription) NextMsgWithContext(ctx context.Context) (*Msg, error) {
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// FlushWithContext will allow a context to control the duration
|
||||
// of a Flush() call. This context should be non-nil and should
|
||||
// have a deadline set. We will return an error if none is present.
|
||||
func (nc *Conn) FlushWithContext(ctx context.Context) error {
|
||||
if nc == nil {
|
||||
return ErrInvalidConnection
|
||||
}
|
||||
if ctx == nil {
|
||||
return ErrInvalidContext
|
||||
}
|
||||
_, ok := ctx.Deadline()
|
||||
if !ok {
|
||||
return ErrNoDeadlineContext
|
||||
}
|
||||
|
||||
nc.mu.Lock()
|
||||
if nc.isClosed() {
|
||||
nc.mu.Unlock()
|
||||
return ErrConnectionClosed
|
||||
}
|
||||
// Create a buffered channel to prevent chan send to block
|
||||
// in processPong()
|
||||
ch := make(chan struct{}, 1)
|
||||
nc.sendPing(ch)
|
||||
nc.mu.Unlock()
|
||||
|
||||
var err error
|
||||
|
||||
select {
|
||||
case _, ok := <-ch:
|
||||
if !ok {
|
||||
err = ErrConnectionClosed
|
||||
} else {
|
||||
close(ch)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
err = ctx.Err()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
nc.removeFlushEntry(ch)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// RequestWithContext will create an Inbox and perform a Request
|
||||
// using the provided cancellation context with the Inbox reply
|
||||
// for the data v. A response will be decoded into the vPtrResponse.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user