Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ func (h *Handler) setupRouter(address string) (*echo.Echo, error) {
e.Use(middleware.Recover())
}

if h.conf.HttpBasicAuth.Password != "" {
username := h.conf.HttpBasicAuth.Username
password := h.conf.HttpBasicAuth.Password
e.Use(middleware.BasicAuth(func(u, p string, _ echo.Context) (bool, error) {
return u == username && p == password, nil
}))
}

// Routes

// Metrics
Expand Down Expand Up @@ -205,10 +213,15 @@ func (cv *customValidator) Validate(i interface{}) error {

type Error struct {
Message string `json:"error"`
// AuthMessage is an error from Echo framework, particularly from Basic Auth middleware
AuthMessage string `json:"message"`
}

func (e Error) Error() string {
return e.Message
if e.Message != "" && e.AuthMessage != "" {
return fmt.Sprintf("error: %s; message: %s", e.Message, e.AuthMessage)
}
return e.Message + e.AuthMessage
}

func ErrorMessage(message string) Error {
Expand Down
29 changes: 27 additions & 2 deletions api/apiclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package apiclient
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
Expand Down Expand Up @@ -30,6 +31,30 @@ func New(address string) *Client {
}
}

func NewWithAuth(address, username, password string) *Client {
c := New(address)
if password != "" {
c.cli.Transport = &basicAuthTransport{
username: username,
password: password,
inner: c.cli.Transport,
}
}
return c
}

type basicAuthTransport struct {
username string
password string
inner http.RoundTripper
}

func (t *basicAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
req = req.Clone(req.Context())
req.SetBasicAuth(t.username, t.password)
return t.inner.RoundTrip(req)
}

func (c *Client) KnownPeers() ([]entity.KnownPeersResponse, error) {
knownPeers := make([]entity.KnownPeersResponse, 0)
err := c.sendGetRequest(api.GetKnownPeersPath, &knownPeers)
Expand Down Expand Up @@ -206,9 +231,9 @@ func (c *Client) readResponseBody(resp *http.Response, responseRef interface{})
apiError := api.Error{}
err := json.NewDecoder(resp.Body).Decode(&apiError)
if err != nil {
return err
return fmt.Errorf("status code: %d, error decoding json: %w", resp.StatusCode, err)
}
return apiError
return fmt.Errorf("status code: %d, error: %w", resp.StatusCode, apiError)
} else if responseRef != nil {
return json.NewDecoder(resp.Body).Decode(responseRef)
}
Expand Down
4 changes: 2 additions & 2 deletions application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestRemovePeer(t *testing.T) {
ts.NoError(err)

peer2From1, err := peer1.api.KnownPeerConfig(peer2.PeerID())
ts.EqualError(err, "peer not found")
ts.EqualError(err, "status code: 404, error: peer not found")
ts.Nil(peer2From1)
_, blockedPeerExists := peer1.app.Conf.GetBlockedPeer(peer2.PeerID())
ts.True(blockedPeerExists)
Expand Down Expand Up @@ -262,7 +262,7 @@ func TestUniquePeerAlias(t *testing.T) {
time.Sleep(200 * time.Millisecond)

err = peer1.api.SendFriendRequest(peer3.PeerID(), "peer", "")
ts.EqualError(err, api.ErrorPeerAliasIsNotUniq)
ts.EqualError(err, "status code: 400, error: "+api.ErrorPeerAliasIsNotUniq)
}

func TestUpdateUseAsExitNodeConfig(t *testing.T) {
Expand Down
27 changes: 22 additions & 5 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ func (a *Application) init() {
Usage: fmt.Sprintf("awl api address, example: %s", defaultApiAddr),
Required: false,
},
&cli.StringFlag{
Name: "api_user",
Usage: "username for api basic auth",
Required: false,
},
&cli.StringFlag{
Name: "api_password",
Usage: "password for api basic auth",
Required: false,
},
},
Commands: []*cli.Command{
{
Expand Down Expand Up @@ -466,17 +476,24 @@ func (a *Application) init() {
}

func (a *Application) initApiConnection(c *cli.Context) error {
username := c.String("api_user")
password := c.String("api_password")

apiAddr := c.String("api_addr")
if apiAddr != "" {
return a.initApiFromAddr(apiAddr)
return a.initApiFromAddr(apiAddr, username, password)
}

conf, errConfig := config.LoadConfig(eventbus.NewBus())
if errConfig == nil {
return a.initApiFromAddr(conf.HttpListenAddress)
if username == "" && password == "" {
username = conf.HttpBasicAuth.Username
password = conf.HttpBasicAuth.Password
}
return a.initApiFromAddr(conf.HttpListenAddress, username, password)
}

errDefault := a.initApiFromAddr(defaultApiAddr)
errDefault := a.initApiFromAddr(defaultApiAddr, username, password)
if errDefault == nil {
return nil
}
Expand All @@ -487,8 +504,8 @@ func (a *Application) initApiConnection(c *cli.Context) error {
return errors.New("no connection to api server")
}

func (a *Application) initApiFromAddr(addr string) error {
api := apiclient.New(addr)
func (a *Application) initApiFromAddr(addr, username, password string) error {
api := apiclient.NewWithAuth(addr, username, password)
_, err := api.PeerInfo()
if err != nil {
return fmt.Errorf("could not access api on address %s: %v", addr, err)
Expand Down
5 changes: 5 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type (
LoggerLevel string `json:"loggerLevel"`
HttpListenAddress string `json:"httpListenAddress"`
HttpListenOnAdminHost bool `json:"httpListenOnAdminHost"`
HttpBasicAuth HttpBasicAuthConfig `json:"httpBasicAuth"`
P2pNode P2pNodeConfig `json:"p2pNode"`
VPNConfig VPNConfig `json:"vpn"`
SOCKS5 SOCKS5Config `json:"socks5"`
Expand Down Expand Up @@ -123,6 +124,10 @@ type (
TrayAutoCheckEnabled bool `json:"trayAutoCheckEnabled"`
TrayAutoCheckInterval string `json:"trayAutoCheckInterval"`
}
HttpBasicAuthConfig struct {
Username string `json:"username"`
Password string `json:"password"`
}
)

func (c *Config) Save() {
Expand Down
10 changes: 3 additions & 7 deletions test_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
"github.com/libp2p/go-libp2p/p2p/host/eventbus"
"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoremem"
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
simlibp2p "github.com/libp2p/go-libp2p/x/simlibp2p"
"github.com/libp2p/go-libp2p/x/simlibp2p"
"github.com/marcopolo/simnet"
"github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -87,7 +87,7 @@ func (ts *TestSuite) NewTestPeer(disableLogging bool) TestPeer {
multiaddr.StringCast("/ip4/127.0.0.1/tcp/0"),
multiaddr.StringCast("/ip4/127.0.0.1/udp/0/quic-v1"),
}
return ts.newTestPeer(disableLogging, listenAddrs, nil)
return ts.newTestPeerWithConfig(disableLogging, listenAddrs, nil, nil)
}

type ConfigModifier func(*config.Config)
Expand All @@ -106,10 +106,6 @@ type SOCKS5PeerConfig struct {
ProxyingEnabled bool
}

func (ts *TestSuite) newTestPeer(disableLogging bool, listenAddrs []multiaddr.Multiaddr, extraLibp2pOpts []libp2p.Option) TestPeer {
return ts.newTestPeerWithConfig(disableLogging, listenAddrs, extraLibp2pOpts, nil)
}

func (ts *TestSuite) newTestPeerWithSOCKS5(disableLogging bool, listenAddrs []multiaddr.Multiaddr, extraLibp2pOpts []libp2p.Option, socks5Conf *SOCKS5PeerConfig) TestPeer {
return ts.newTestPeerWithConfig(disableLogging, listenAddrs, extraLibp2pOpts, func(c *config.Config) {
if socks5Conf != nil {
Expand Down Expand Up @@ -178,7 +174,7 @@ func (ts *TestSuite) newTestPeerWithConfig(disableLogging bool, listenAddrs []mu

tp := TestPeer{
app: app,
api: apiclient.New(app.Api.Address()),
api: apiclient.NewWithAuth(app.Api.Address(), app.Conf.HttpBasicAuth.Username, app.Conf.HttpBasicAuth.Password),
tun: testTUN,
}

Expand Down
Loading