Skip to content

Commit

Permalink
Merge pull request #1116 from ersonp/refactor/internal
Browse files Browse the repository at this point in the history
Refactor internal packages
  • Loading branch information
jdknives authored Mar 2, 2022
2 parents 6f691a1 + 93a6d23 commit 41c3731
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 269 deletions.
82 changes: 0 additions & 82 deletions internal/httpauth/auth.go

This file was deleted.

68 changes: 24 additions & 44 deletions internal/httpauth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ const (
invalidNonceErrorMessage = "SW-Nonce does not match"
)

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

// NextNonceResponse represents a ServeHTTP response for json encoding
type NextNonceResponse struct {
Edge cipher.PubKey `json:"edge"`
Expand All @@ -42,14 +47,12 @@ type HTTPError struct {
}

// Client implements Client for auth services.
// As Client needs to dial both with reusing address and without it, it uses two http clients: reuseClient and client.
type Client struct {
// atomic requires 64-bit alignment for struct field access
nonce uint64
mu sync.Mutex
reqMu sync.Mutex
client *http.Client
reuseClient *http.Client
key cipher.PubKey
sec cipher.SecKey
addr string // sanitized address of the client, which may differ from addr used in NewClient
Expand All @@ -67,7 +70,6 @@ func NewClient(ctx context.Context, addr string, key cipher.PubKey, sec cipher.S
mLog *logging.MasterLogger) (*Client, error) {
c := &Client{
client: client,
reuseClient: client,
key: key,
sec: sec,
addr: sanitizedAddr(addr),
Expand All @@ -85,28 +87,6 @@ func NewClient(ctx context.Context, addr string, key cipher.PubKey, sec cipher.S
return c, nil
}

// Header returns headers for httpauth.
func (c *Client) Header() (http.Header, error) {
nonce := c.getCurrentNonce()
body := make([]byte, 0)
sign, err := Sign(body, nonce, c.sec)
if err != nil {
return nil, err
}

header := make(http.Header)

// use nonce, later, if no err from req update such nonce
header.Set("SW-Nonce", strconv.FormatUint(uint64(nonce), 10))
header.Set("SW-Sig", sign.Hex())
header.Set("SW-Public", c.key.Hex())
if c.clientPublicIP != "" {
header.Set("SW-PublicIP", c.clientPublicIP)
}

return header, nil
}

// Do performs a new authenticated Request and returns the response. Internally, if the request was
// successful nonce is incremented
func (c *Client) Do(req *http.Request) (*http.Response, error) {
Expand Down Expand Up @@ -189,7 +169,7 @@ func (c *Client) Nonce(ctx context.Context, key cipher.PubKey) (Nonce, error) {
}()

if resp.StatusCode != http.StatusOK {
return 0, fmt.Errorf("error getting current nonce: status: %d <- %v", resp.StatusCode, extractError(resp.Body))
return 0, fmt.Errorf("error getting current nonce: status: %d <- %v", resp.StatusCode, extractHTTPError(resp.Body))
}

var nr NextNonceResponse
Expand All @@ -200,22 +180,6 @@ func (c *Client) Nonce(ctx context.Context, key cipher.PubKey) (Nonce, error) {
return nr.NextNonce, nil
}

// ReuseClient returns HTTP client that reuses port for dialing.
func (c *Client) ReuseClient() *http.Client {
c.mu.Lock()
defer c.mu.Unlock()

return c.reuseClient
}

// SetTransport sets transport for HTTP client that reuses port for dialing.
func (c *Client) SetTransport(transport http.RoundTripper) {
c.mu.Lock()
defer c.mu.Unlock()

c.reuseClient.Transport = transport
}

// SetNonce sets client current nonce to given nonce
func (c *Client) SetNonce(n Nonce) {
atomic.StoreUint64(&c.nonce, uint64(n))
Expand Down Expand Up @@ -301,8 +265,8 @@ func sanitizedAddr(addr string) string {
return u.String()
}

// extractError returns the decoded error message from Body.
func extractError(r io.Reader) error {
// extractHTTPError returns the decoded error message from Body.
func extractHTTPError(r io.Reader) error {
var serverError HTTPResponse

body, err := ioutil.ReadAll(r)
Expand All @@ -316,3 +280,19 @@ func extractError(r io.Reader) error {

return errors.New(serverError.Error.Message)
}

// 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)
}
22 changes: 22 additions & 0 deletions internal/httpauth/nonce.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package httpauth

import (
"fmt"

"github.com/skycoin/dmsg/cipher"
)

// Nonce is used to sign requests in order to avoid replay attack
type Nonce uint64

func (n Nonce) String() string { return fmt.Sprintf("%d", n) }

// PayloadWithNonce returns the concatenation of payload and nonce.
func PayloadWithNonce(payload []byte, nonce Nonce) []byte {
return []byte(fmt.Sprintf("%s%d", string(payload), nonce))
}

// Sign signs the Hash of payload and nonce
func Sign(payload []byte, nonce Nonce, sec cipher.SecKey) (cipher.Sig, error) {
return cipher.SignPayload(PayloadWithNonce(payload, nonce), sec)
}
24 changes: 0 additions & 24 deletions internal/testhelpers/testhelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,10 @@ package testhelpers

import (
"errors"
"testing"
"time"

"github.com/stretchr/testify/require"
)

const timeout = 5 * time.Second

// NoErr is used with the mock interface to return from its methods.
var NoErr error

// Err is used with the mock interface to return some error from its methods.
var Err = errors.New("error")

// WithinTimeout tries to read an error from error channel within timeout and returns it.
// If timeout exceeds, nil value is returned.
func WithinTimeout(ch <-chan error) error {
select {
case err := <-ch:
return err
case <-time.After(timeout):
return nil
}
}

// NoErrorN performs require.NoError on multiple errors
func NoErrorN(t *testing.T, errs ...error) {
for _, err := range errs {
require.NoError(t, err)
}
}
27 changes: 1 addition & 26 deletions internal/utclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ package utclient
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"

Expand All @@ -21,11 +17,6 @@ import (

//go:generate mockery -name APIClient -case underscore -inpkg

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

// APIClient implements uptime tracker API client.
type APIClient interface {
UpdateVisorUptime(context.Context) error
Expand Down Expand Up @@ -102,24 +93,8 @@ func (c *httpClient) UpdateVisorUptime(ctx context.Context) error {
}()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("status: %d, error: %w", resp.StatusCode, extractError(resp.Body))
return fmt.Errorf("status: %d, error: %w", resp.StatusCode, httpauth.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)
}
32 changes: 0 additions & 32 deletions internal/vpn/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,8 @@ package vpn
import (
"encoding/json"
"fmt"
"io"
"net"
"time"

"github.com/skycoin/dmsg/cipher"
"github.com/skycoin/dmsg/noise"

"github.com/skycoin/skywire/pkg/app/appnet"
)

// WriteJSONWithTimeout marshals `data` and sends it over the `conn` with the specified write `timeout`.
Expand Down Expand Up @@ -92,29 +86,3 @@ func ReadJSON(conn net.Conn, data interface{}) error {

return nil
}

// WrapRWWithNoise wraps `conn` with noise.
func WrapRWWithNoise(conn net.Conn, initiator bool, pk cipher.PubKey, sk cipher.SecKey) (io.ReadWriter, error) {
remoteAddr, isAppConn := conn.RemoteAddr().(appnet.Addr)
if isAppConn {
ns, err := noise.New(noise.HandshakeKK, noise.Config{
LocalPK: pk,
LocalSK: sk,
RemotePK: remoteAddr.PubKey,
Initiator: initiator,
})
if err != nil {
return nil, fmt.Errorf("failed to prepare stream noise object: %w", err)
}

rw := noise.NewReadWriter(conn, ns)
if err := rw.Handshake(HSTimeout); err != nil {
return nil, fmt.Errorf("error performing noise handshake: %w", err)
}

return rw, nil
}

// shouldn't happen, but no encryption in this case
return conn, nil
}
Loading

0 comments on commit 41c3731

Please sign in to comment.