Skip to content

Commit

Permalink
Merge branch 'mainnet-milestone1' of https://github.com/skycoin/skywire
Browse files Browse the repository at this point in the history
… into fix/rule-expiration
  • Loading branch information
Darkren committed Aug 22, 2019
2 parents 6032609 + 1aadc31 commit 0689138
Show file tree
Hide file tree
Showing 64 changed files with 1,133 additions and 1,373 deletions.
2 changes: 2 additions & 0 deletions cmd/skywire-cli/commands/node/gen-config.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ func defaultConfig() *visor.Config {

conf.Hypervisors = []visor.HypervisorConfig{}

conf.Uptime.Tracker = ""

conf.AppsPath = "./apps"
conf.LocalPath = "./local"

Expand Down
4 changes: 2 additions & 2 deletions cmd/skywire-cli/commands/node/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ var addRuleCmd = &cobra.Command{
remotePort = routing.Port(parseUint("remote-port", args[3], 16))
localPort = routing.Port(parseUint("local-port", args[4], 16))
)
rule = routing.AppRule(time.Now().Add(expire), routeID, remotePK, remotePort, localPort)
rule = routing.AppRule(time.Now().Add(expire), routeID, remotePK, remotePort, localPort, 0)
case "fwd":
var (
nextRouteID = routing.RouteID(parseUint("next-route-id", args[1], 32))
nextTpID = internal.ParseUUID("next-transport-id", args[2])
)
rule = routing.ForwardRule(time.Now().Add(expire), nextRouteID, nextTpID)
rule = routing.ForwardRule(time.Now().Add(expire), nextRouteID, nextTpID, 0)
}
rIDKey, err := rpcClient().AddRoutingRule(rule)
internal.Catch(err)
Expand Down
21 changes: 21 additions & 0 deletions cmd/skywire-visor/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package commands

import (
"bufio"
"context"
"encoding/json"
"fmt"
"io"
Expand All @@ -22,6 +23,7 @@ import (
"github.com/skycoin/skycoin/src/util/logging"
"github.com/spf13/cobra"

"github.com/skycoin/skywire/internal/utclient"
"github.com/skycoin/skywire/pkg/util/pathutil"
"github.com/skycoin/skywire/pkg/visor"
)
Expand Down Expand Up @@ -148,6 +150,25 @@ func (cfg *runCfg) runNode() *runCfg {
cfg.logger.Fatal("Failed to initialize node: ", err)
}

if cfg.conf.Uptime.Tracker != "" {
uptimeTracker, err := utclient.NewHTTP(cfg.conf.Uptime.Tracker, cfg.conf.Node.StaticPubKey, cfg.conf.Node.StaticSecKey)
if err != nil {
cfg.logger.Error("Failed to connect to uptime tracker: ", err)
} else {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()

go func() {
for range ticker.C {
ctx := context.Background()
if err := uptimeTracker.UpdateNodeUptime(ctx); err != nil {
cfg.logger.Error("Failed to update node uptime: ", err)
}
}
}()
}
}

go func() {
if err := node.Start(); err != nil {
cfg.logger.Fatal("Failed to start node: ", err)
Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ require (
github.com/prometheus/client_golang v1.0.0
github.com/prometheus/common v0.4.1
github.com/sirupsen/logrus v1.4.2
github.com/skycoin/dmsg v0.0.0-20190805065636-70f4c32a994f
github.com/skycoin/dmsg v0.0.0-20190816104216-d18ee6aa05cb
github.com/skycoin/skycoin v0.26.0
github.com/spf13/cobra v0.0.5
github.com/stretchr/testify v1.3.0
go.etcd.io/bbolt v1.3.3
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect
golang.org/x/tools v0.0.0-20190805222050-c5a2fd39b72a // indirect
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect
golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7 // indirect
)

// Uncomment for tests with alternate branches of 'dmsg'
replace github.com/skycoin/dmsg => ../dmsg
//replace github.com/skycoin/dmsg => ../dmsg
13 changes: 13 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/skycoin/dmsg v0.0.0-20190805065636-70f4c32a994f h1:WWjaxOXoj6oYelm67MNtJbg51HQALjKAyhs2WAHgpZs=
github.com/skycoin/dmsg v0.0.0-20190805065636-70f4c32a994f/go.mod h1:obZYZp8eKR7Xqz+KNhJdUE6Gvp6rEXbDO8YTlW2YXgU=
github.com/skycoin/dmsg v0.0.0-20190816104216-d18ee6aa05cb h1:kpNxP3mOjrVyyLBOtOxBgpxUOCBBI/RhdO9Vto5+OHk=
github.com/skycoin/dmsg v0.0.0-20190816104216-d18ee6aa05cb/go.mod h1:obZYZp8eKR7Xqz+KNhJdUE6Gvp6rEXbDO8YTlW2YXgU=
github.com/skycoin/skycoin v0.26.0 h1:xDxe2r8AclMntZ550Y/vUQgwgLtwrf9Wu5UYiYcN5/o=
github.com/skycoin/skycoin v0.26.0/go.mod h1:78nHjQzd8KG0jJJVL/j0xMmrihXi70ti63fh8vXScJw=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
Expand All @@ -116,12 +118,16 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
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/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -135,13 +141,20 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M=
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190627182818-9947fec5c3ab/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190802220118-1d1727260058/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190805222050-c5a2fd39b72a h1:0AGI+cC4FJwXNdClvHzfHhJf/yPjKwdo/+m0lPKrdJA=
golang.org/x/tools v0.0.0-20190805222050-c5a2fd39b72a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479 h1:lfN2PY/jymfnxkNHlbBF5DwPsUvhqUnrdgfK01iH2s0=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7 h1:PVCvyir09Xgta5zksNZDkrL+eSm/Y+gQxRG3IfqNQ3A=
golang.org/x/tools v0.0.0-20190821162956-65e3620a7ae7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
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=
Expand Down
4 changes: 2 additions & 2 deletions internal/testhelpers/testhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (

const timeout = 5 * time.Second

// NoErrorWithinTimeout tries to read an error from error channel within timeout and returns it.
// WithinTimeout tries to read an error from error channel within timeout and returns it.
// If timeout exceeds, nil value is returned.
func NoErrorWithinTimeout(ch <-chan error) error {
func WithinTimeout(ch <-chan error) error {
select {
case err := <-ch:
return err
Expand Down
90 changes: 90 additions & 0 deletions internal/utclient/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Package utclient implements uptime tracker client
package utclient

import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"

"github.com/skycoin/dmsg/cipher"

"github.com/skycoin/skywire/internal/httpauth"
)

// Error is the object returned to the client when there's an error.
type Error struct {
Error string `json:"error"`
}

// APIClient implements messaging discovery API client.
type APIClient interface {
UpdateNodeUptime(context.Context) error
}

// httpClient implements Client for uptime tracker API.
type httpClient struct {
client *httpauth.Client
pk cipher.PubKey
sk cipher.SecKey
}

// NewHTTP creates a new client setting a public key to the client to be used for auth.
// When keys are set, the client will sign request before submitting.
// The signature information is transmitted in the header using:
// * SW-Public: The specified public key
// * SW-Nonce: The nonce for that public key
// * SW-Sig: The signature of the payload + the nonce
func NewHTTP(addr string, pk cipher.PubKey, sk cipher.SecKey) (APIClient, error) {
client, err := httpauth.NewClient(context.Background(), addr, pk, sk)
if err != nil {
return nil, fmt.Errorf("httpauth: %s", err)
}

return &httpClient{client: client, pk: pk, sk: sk}, nil
}

// Get performs a new GET request.
func (c *httpClient) Get(ctx context.Context, path string) (*http.Response, error) {
req, err := http.NewRequest("GET", c.client.Addr()+path, new(bytes.Buffer))
if err != nil {
return nil, err
}

return c.client.Do(req.WithContext(ctx))
}

// UpdateNodeUptime updates node uptime.
func (c *httpClient) UpdateNodeUptime(ctx context.Context) error {
resp, err := c.Get(ctx, "/update")
if err != nil {
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("status: %d, error: %v", resp.StatusCode, extractError(resp.Body))
}

return nil
}

// extractError returns the decoded error message from Body.
func extractError(r io.Reader) error {
var apiError Error

body, err := ioutil.ReadAll(r)
if err != nil {
return err
}

if err := json.Unmarshal(body, &apiError); err != nil {
return errors.New(string(body))
}

return errors.New(apiError.Error)
}
83 changes: 83 additions & 0 deletions internal/utclient/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package utclient

import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"sync"
"testing"

"github.com/skycoin/dmsg/cipher"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/skycoin/skywire/internal/httpauth"
)

var testPubKey, testSecKey = cipher.GenerateKeyPair()

func TestClientAuth(t *testing.T) {
wg := sync.WaitGroup{}

headerCh := make(chan http.Header, 1)
srv := httptest.NewServer(http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
switch url := r.URL.String(); url {
case "/":
defer wg.Done()
headerCh <- r.Header

case fmt.Sprintf("/security/nonces/%s", testPubKey):
fmt.Fprintf(w, `{"edge": "%s", "next_nonce": 1}`, testPubKey)

default:
t.Errorf("Don't know how to handle URL = '%s'", url)
}
},
))
defer srv.Close()

client, err := NewHTTP(srv.URL, testPubKey, testSecKey)
require.NoError(t, err)
c := client.(*httpClient)

wg.Add(1)
_, err = c.Get(context.TODO(), "/")
require.NoError(t, err)

header := <-headerCh
assert.Equal(t, testPubKey.Hex(), header.Get("SW-Public"))
assert.Equal(t, "1", header.Get("SW-Nonce"))
assert.NotEmpty(t, header.Get("SW-Sig")) // TODO: check for the right key

wg.Wait()
}

func TestUpdateNodeUptime(t *testing.T) {
urlCh := make(chan string, 1)
srv := httptest.NewServer(authHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
urlCh <- r.URL.String()
})))
defer srv.Close()

c, err := NewHTTP(srv.URL, testPubKey, testSecKey)
require.NoError(t, err)

err = c.UpdateNodeUptime(context.TODO())
require.NoError(t, err)

assert.Equal(t, "/update", <-urlCh)
}

func authHandler(next http.Handler) http.Handler {
m := http.NewServeMux()
m.Handle("/security/nonces/", http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(&httpauth.NextNonceResponse{Edge: testPubKey, NextNonce: 1}) // nolint: errcheck
},
))
m.Handle("/", next)
return m
}
23 changes: 23 additions & 0 deletions pkg/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,28 @@ func SetupFromPipe(config *Config, inFD, outFD uintptr) (*App, error) {
return app, nil
}

// New creates a new App directly from a `net.Conn` implementation.
func New(conn net.Conn, conf *Config) (*App, error) {
app := &App{
config: *conf,
proto: NewProtocol(conn),
acceptChan: make(chan [2]routing.Addr),
doneChan: make(chan struct{}),
conns: make(map[routing.Loop]io.ReadWriteCloser),
}

go app.handleProto()

if err := app.proto.Send(FrameInit, conf, nil); err != nil {
if err := app.Close(); err != nil {
log.WithError(err).Warn("Failed to close app")
}
return nil, fmt.Errorf("INIT handshake failed: %s", err)
}

return app, nil
}

// Setup setups app using default pair of pipes
func Setup(config *Config) (*App, error) {
return SetupFromPipe(config, DefaultIn, DefaultOut)
Expand Down Expand Up @@ -197,6 +219,7 @@ func (app *App) serveConn(loop routing.Loop, conn io.ReadWriteCloser) {
if err != nil {
break
}
fmt.Println("READ:", buf)

packet := &Packet{Loop: loop, Payload: buf[:n]}
if err := app.proto.Send(FrameSend, packet, nil); err != nil {
Expand Down
Loading

0 comments on commit 0689138

Please sign in to comment.