Skip to content
Snippets Groups Projects
Unverified Commit fa05123e authored by Angelo Capossele's avatar Angelo Capossele Committed by GitHub
Browse files

Merge pull request #169 from iotaledger/refactor/webapi

Refactors web API
parents 65a91713 506dee9d
No related branches found
No related tags found
No related merge requests found
// Implements a very simple wrapper for GoShimmer's HTTP API . // Implements a very simple wrapper for GoShimmer's web API .
package goshimmer package goshimmer
import ( import (
...@@ -6,16 +6,18 @@ import ( ...@@ -6,16 +6,18 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
webapi_broadcastData "github.com/iotaledger/goshimmer/plugins/webapi/broadcastData" webapi_broadcastData "github.com/iotaledger/goshimmer/plugins/webapi/broadcastData"
webapi_findTransactions "github.com/iotaledger/goshimmer/plugins/webapi/findTransactions" webapi_findTransactionHashes "github.com/iotaledger/goshimmer/plugins/webapi/findTransactionHashes"
webapi_getNeighbors "github.com/iotaledger/goshimmer/plugins/webapi/getNeighbors" webapi_getNeighbors "github.com/iotaledger/goshimmer/plugins/webapi/getNeighbors"
webapi_getTransactions "github.com/iotaledger/goshimmer/plugins/webapi/getTransactions" webapi_getTransactionObjectsByHash "github.com/iotaledger/goshimmer/plugins/webapi/getTransactionObjectsByHash"
webapi_getTrytes "github.com/iotaledger/goshimmer/plugins/webapi/getTrytes" webapi_getTransactionTrytesByHash "github.com/iotaledger/goshimmer/plugins/webapi/getTransactionTrytesByHash"
webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi/gtta" webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi/gtta"
webapi_spammer "github.com/iotaledger/goshimmer/plugins/webapi/spammer" webapi_spammer "github.com/iotaledger/goshimmer/plugins/webapi/spammer"
webapi_auth "github.com/iotaledger/goshimmer/plugins/webauth"
"github.com/iotaledger/iota.go/consts" "github.com/iotaledger/iota.go/consts"
"github.com/iotaledger/iota.go/guards" "github.com/iotaledger/iota.go/guards"
"github.com/iotaledger/iota.go/trinary" "github.com/iotaledger/iota.go/trinary"
...@@ -25,17 +27,19 @@ var ( ...@@ -25,17 +27,19 @@ var (
ErrBadRequest = errors.New("bad request") ErrBadRequest = errors.New("bad request")
ErrInternalServerError = errors.New("internal server error") ErrInternalServerError = errors.New("internal server error")
ErrNotFound = errors.New("not found") ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrUnknownError = errors.New("unknown error") ErrUnknownError = errors.New("unknown error")
) )
const ( const (
routeBroadcastData = "broadcastData" routeBroadcastData = "broadcastData"
routeGetTrytes = "getTrytes" routeGetTransactionTrytesByHash = "getTransactionTrytesByHash"
routeGetTransactions = "getTransactions" routeGetTransactionObjectsByHash = "getTransactionObjectsByHash"
routeFindTransactions = "findTransactions" routeFindTransactionsHashes = "findTransactionHashes"
routeGetNeighbors = "getNeighbors" routeGetNeighbors = "getNeighbors"
routeGetTransactionsToApprove = "getTransactionsToApprove" routeGetTransactionsToApprove = "getTransactionsToApprove"
routeSpammer = "spammer" routeSpammer = "spammer"
routeLogin = "login"
contentTypeJSON = "application/json" contentTypeJSON = "application/json"
) )
...@@ -47,9 +51,11 @@ func NewGoShimmerAPI(node string, httpClient ...http.Client) *GoShimmerAPI { ...@@ -47,9 +51,11 @@ func NewGoShimmerAPI(node string, httpClient ...http.Client) *GoShimmerAPI {
return &GoShimmerAPI{node: node} return &GoShimmerAPI{node: node}
} }
// GoShimmerAPI is an API wrapper over the web API of GoShimmer.
type GoShimmerAPI struct { type GoShimmerAPI struct {
httpClient http.Client httpClient http.Client
node string node string
jwt string
} }
type errorresponse struct { type errorresponse struct {
...@@ -79,152 +85,168 @@ func interpretBody(res *http.Response, decodeTo interface{}) error { ...@@ -79,152 +85,168 @@ func interpretBody(res *http.Response, decodeTo interface{}) error {
return fmt.Errorf("%w: %s", ErrNotFound, errRes.Error) return fmt.Errorf("%w: %s", ErrNotFound, errRes.Error)
case http.StatusBadRequest: case http.StatusBadRequest:
return fmt.Errorf("%w: %s", ErrBadRequest, errRes.Error) return fmt.Errorf("%w: %s", ErrBadRequest, errRes.Error)
case http.StatusUnauthorized:
return fmt.Errorf("%w: %s", ErrUnauthorized, errRes.Error)
} }
return fmt.Errorf("%w: %s", ErrUnknownError, errRes.Error) return fmt.Errorf("%w: %s", ErrUnknownError, errRes.Error)
} }
func (api *GoShimmerAPI) BroadcastData(targetAddress trinary.Trytes, data string) (trinary.Hash, error) { func (api *GoShimmerAPI) do(method string, route string, reqObj interface{}, resObj interface{}) error {
if !guards.IsHash(targetAddress) { // marshal request object
return "", fmt.Errorf("%w: invalid address: %s", consts.ErrInvalidHash, targetAddress) var data []byte
if reqObj != nil {
var err error
data, err = json.Marshal(reqObj)
if err != nil {
return err
}
} }
reqBytes, err := json.Marshal(&webapi_broadcastData.Request{Address: targetAddress, Data: data}) // construct request
req, err := http.NewRequest(method, fmt.Sprintf("%s/%s", api.node, route), func() io.Reader {
if data == nil {
return nil
}
return bytes.NewReader(data)
}())
if err != nil { if err != nil {
return "", err return err
} }
res, err := api.httpClient.Post(fmt.Sprintf("%s/%s", api.node, routeBroadcastData), contentTypeJSON, bytes.NewReader(reqBytes)) // add authorization header with JWT
if err != nil { if len(api.jwt) > 0 {
return "", err req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", api.jwt))
} }
resObj := &webapi_broadcastData.Response{} // make the request
if err := interpretBody(res, resObj); err != nil { res, err := api.httpClient.Do(req)
return "", err if err != nil {
return err
} }
return resObj.Hash, nil if resObj == nil {
} return nil
}
func (api *GoShimmerAPI) GetTrytes(txHashes trinary.Hashes) ([]trinary.Trytes, error) { // write response into response object
for _, hash := range txHashes { if err := interpretBody(res, resObj); err != nil {
if !guards.IsTrytes(hash) { return err
return nil, fmt.Errorf("%w: invalid hash: %s", consts.ErrInvalidHash, hash)
}
} }
return nil
}
reqBytes, err := json.Marshal(&webapi_getTrytes.Request{Hashes: txHashes}) // Login authorizes this API instance against the web API.
if err != nil { // You must call this function before any before any other call, if the web-auth plugin is enabled.
return nil, err func (api *GoShimmerAPI) Login(username string, password string) error {
res := &webapi_auth.Response{}
if err := api.do(http.MethodPost, routeLogin,
&webapi_auth.Request{Username: username, Password: password}, res); err != nil {
return err
} }
api.jwt = res.Token
return nil
}
res, err := api.httpClient.Post(fmt.Sprintf("%s/%s", api.node, routeGetTrytes), contentTypeJSON, bytes.NewReader(reqBytes)) // BroadcastData sends the given data by creating a zero value transaction in the backend targeting the given address.
if err != nil { func (api *GoShimmerAPI) BroadcastData(targetAddress trinary.Trytes, data string) (trinary.Hash, error) {
return nil, err if !guards.IsHash(targetAddress) {
return "", fmt.Errorf("%w: invalid address: %s", consts.ErrInvalidHash, targetAddress)
} }
resObj := &webapi_getTrytes.Response{} res := &webapi_broadcastData.Response{}
if err := interpretBody(res, resObj); err != nil { if err := api.do(http.MethodPost, routeBroadcastData,
return nil, err &webapi_broadcastData.Request{Address: targetAddress, Data: data}, res); err != nil {
return "", err
} }
return resObj.Trytes, nil return res.Hash, nil
} }
func (api *GoShimmerAPI) GetTransactions(txHashes trinary.Hashes) ([]webapi_getTransactions.Transaction, error) { // GetTransactionTrytesByHash gets the corresponding transaction trytes given the transaction hashes.
func (api *GoShimmerAPI) GetTransactionTrytesByHash(txHashes trinary.Hashes) ([]trinary.Trytes, error) {
for _, hash := range txHashes { for _, hash := range txHashes {
if !guards.IsTrytes(hash) { if !guards.IsTrytes(hash) {
return nil, fmt.Errorf("%w: invalid hash: %s", consts.ErrInvalidHash, hash) return nil, fmt.Errorf("%w: invalid hash: %s", consts.ErrInvalidHash, hash)
} }
} }
reqBytes, err := json.Marshal(&webapi_getTransactions.Request{Hashes: txHashes}) res := &webapi_getTransactionTrytesByHash.Response{}
if err != nil { if err := api.do(http.MethodPost, routeGetTransactionTrytesByHash,
return nil, err &webapi_getTransactionTrytesByHash.Request{Hashes: txHashes}, res); err != nil {
}
res, err := api.httpClient.Post(fmt.Sprintf("%s/%s", api.node, routeGetTransactions), contentTypeJSON, bytes.NewReader(reqBytes))
if err != nil {
return nil, err
}
resObj := &webapi_getTransactions.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err return nil, err
} }
return resObj.Transactions, nil return res.Trytes, nil
} }
func (api *GoShimmerAPI) FindTransactions(query *webapi_findTransactions.Request) ([]trinary.Hashes, error) { // GetTransactionObjectsByHash gets the transaction objects given the transaction hashes.
for _, hash := range query.Addresses { func (api *GoShimmerAPI) GetTransactionObjectsByHash(txHashes trinary.Hashes) ([]webapi_getTransactionObjectsByHash.Transaction, error) {
for _, hash := range txHashes {
if !guards.IsTrytes(hash) { if !guards.IsTrytes(hash) {
return nil, fmt.Errorf("%w: invalid hash: %s", consts.ErrInvalidHash, hash) return nil, fmt.Errorf("%w: invalid hash: %s", consts.ErrInvalidHash, hash)
} }
} }
reqBytes, err := json.Marshal(&query) res := &webapi_getTransactionObjectsByHash.Response{}
if err != nil { if err := api.do(http.MethodPost, routeGetTransactionObjectsByHash,
&webapi_getTransactionObjectsByHash.Request{Hashes: txHashes}, res); err != nil {
return nil, err return nil, err
} }
res, err := api.httpClient.Post(fmt.Sprintf("%s/%s", api.node, routeFindTransactions), contentTypeJSON, bytes.NewReader(reqBytes)) return res.Transactions, nil
if err != nil {
return nil, err
}
resObj := &webapi_findTransactions.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err
}
return resObj.Transactions, nil
} }
func (api *GoShimmerAPI) GetNeighbors() (*webapi_getNeighbors.Response, error) { // FindTransactionHashes finds the given transaction hashes given the query.
res, err := api.httpClient.Get(fmt.Sprintf("%s/%s", api.node, routeGetNeighbors)) func (api *GoShimmerAPI) FindTransactionHashes(query *webapi_findTransactionHashes.Request) ([]trinary.Hashes, error) {
if err != nil { for _, hash := range query.Addresses {
return nil, err if !guards.IsTrytes(hash) {
return nil, fmt.Errorf("%w: invalid hash: %s", consts.ErrInvalidHash, hash)
}
} }
resObj := &webapi_getNeighbors.Response{} res := &webapi_findTransactionHashes.Response{}
if err := interpretBody(res, resObj); err != nil { if err := api.do(http.MethodPost, routeFindTransactionsHashes, query, res); err != nil {
return nil, err return nil, err
} }
return resObj, nil return res.Transactions, nil
} }
func (api *GoShimmerAPI) GetTips() (*webapi_gtta.Response, error) { // GetNeighbors gets the chosen/accepted neighbors.
res, err := api.httpClient.Get(fmt.Sprintf("%s/%s", api.node, routeGetTransactionsToApprove)) // If knownPeers is set, also all known peers to the node are returned additionally.
if err != nil { func (api *GoShimmerAPI) GetNeighbors(knownPeers bool) (*webapi_getNeighbors.Response, error) {
res := &webapi_getNeighbors.Response{}
if err := api.do(http.MethodGet, func() string {
if !knownPeers {
return routeGetNeighbors
}
return fmt.Sprintf("%s?known=1", routeGetNeighbors)
}(), nil, res); err != nil {
return nil, err return nil, err
} }
return res, nil
}
resObj := &webapi_gtta.Response{} // GetTips executes the tip-selection on the node to retrieve tips to approve.
if err := interpretBody(res, resObj); err != nil { func (api *GoShimmerAPI) GetTransactionsToApprove() (*webapi_gtta.Response, error) {
res := &webapi_gtta.Response{}
if err := api.do(http.MethodGet, routeGetTransactionsToApprove, nil, res); err != nil {
return nil, err return nil, err
} }
return res, nil
return resObj, nil
} }
// ToggleSpammer toggles the node internal spammer.
func (api *GoShimmerAPI) ToggleSpammer(enable bool) (*webapi_spammer.Response, error) { func (api *GoShimmerAPI) ToggleSpammer(enable bool) (*webapi_spammer.Response, error) {
res, err := api.httpClient.Get(fmt.Sprintf("%s/%s?cmd=%s", api.node, routeSpammer, func() string { res := &webapi_spammer.Response{}
if err := api.do(http.MethodGet, func() string {
if enable { if enable {
return "start" return fmt.Sprintf("%s?cmd=start", routeSpammer)
} }
return "stop" return fmt.Sprintf("%s?cmd=stop", routeSpammer)
}())) }(), nil, res); err != nil {
if err != nil {
return nil, err
}
resObj := &webapi_spammer.Response{}
if err := interpretBody(res, resObj); err != nil {
return nil, err return nil, err
} }
return res, nil
return resObj, nil
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
"entrynodes": [ "entrynodes": [
"V8LYtWWcPYYDTTXLeIEFjJEuWlsjDiI0+Pq/Cx9ai6g=@116.202.49.178:14626" "V8LYtWWcPYYDTTXLeIEFjJEuWlsjDiI0+Pq/Cx9ai6g=@116.202.49.178:14626"
], ],
"port":14626 "port": 14626
}, },
"database": { "database": {
"directory": "mainnetdb" "directory": "mainnetdb"
...@@ -16,6 +16,14 @@ ...@@ -16,6 +16,14 @@
"gossip": { "gossip": {
"port": 14666 "port": 14666
}, },
"webapi": {
"bindAddress": "0.0.0.0:8080",
"auth": {
"username": "goshimmer",
"password": "goshimmer",
"privateKey": "uUUavNbdr32jE9CqnSMCKt4HMu9AZ2K4rKekUSPx9jk83eyeM7xewv5CqUKYMC9"
}
},
"graph": { "graph": {
"webrootPath": "./IOTAtangle/webroot", "webrootPath": "./IOTAtangle/webroot",
"socketioPath": "./socket.io-client/dist/socket.io.js", "socketioPath": "./socket.io-client/dist/socket.io.js",
......
...@@ -20,13 +20,13 @@ import ( ...@@ -20,13 +20,13 @@ import (
"github.com/iotaledger/goshimmer/plugins/ui" "github.com/iotaledger/goshimmer/plugins/ui"
"github.com/iotaledger/goshimmer/plugins/webapi" "github.com/iotaledger/goshimmer/plugins/webapi"
webapi_broadcastData "github.com/iotaledger/goshimmer/plugins/webapi/broadcastData" webapi_broadcastData "github.com/iotaledger/goshimmer/plugins/webapi/broadcastData"
webapi_findTransactions "github.com/iotaledger/goshimmer/plugins/webapi/findTransactions" webapi_findTransactionHashes "github.com/iotaledger/goshimmer/plugins/webapi/findTransactionHashes"
webapi_getNeighbors "github.com/iotaledger/goshimmer/plugins/webapi/getNeighbors" webapi_getNeighbors "github.com/iotaledger/goshimmer/plugins/webapi/getNeighbors"
webapi_getTransactions "github.com/iotaledger/goshimmer/plugins/webapi/getTransactions" webapi_getTransactionObjectsByHash "github.com/iotaledger/goshimmer/plugins/webapi/getTransactionObjectsByHash"
webapi_getTrytes "github.com/iotaledger/goshimmer/plugins/webapi/getTrytes" webapi_getTransactionTrytesByHash "github.com/iotaledger/goshimmer/plugins/webapi/getTransactionTrytesByHash"
webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi/gtta" webapi_gtta "github.com/iotaledger/goshimmer/plugins/webapi/gtta"
webapi_spammer "github.com/iotaledger/goshimmer/plugins/webapi/spammer" webapi_spammer "github.com/iotaledger/goshimmer/plugins/webapi/spammer"
"github.com/iotaledger/goshimmer/plugins/webauth" webapi_auth "github.com/iotaledger/goshimmer/plugins/webauth"
"github.com/iotaledger/goshimmer/plugins/zeromq" "github.com/iotaledger/goshimmer/plugins/zeromq"
"github.com/iotaledger/hive.go/node" "github.com/iotaledger/hive.go/node"
) )
...@@ -54,17 +54,17 @@ func main() { ...@@ -54,17 +54,17 @@ func main() {
statusscreen_tps.PLUGIN, statusscreen_tps.PLUGIN,
webapi.PLUGIN, webapi.PLUGIN,
webapi_auth.PLUGIN,
webapi_gtta.PLUGIN, webapi_gtta.PLUGIN,
webapi_spammer.PLUGIN, webapi_spammer.PLUGIN,
webapi_broadcastData.PLUGIN, webapi_broadcastData.PLUGIN,
webapi_getTrytes.PLUGIN, webapi_getTransactionTrytesByHash.PLUGIN,
webapi_getTransactions.PLUGIN, webapi_getTransactionObjectsByHash.PLUGIN,
webapi_findTransactions.PLUGIN, webapi_findTransactionHashes.PLUGIN,
webapi_getNeighbors.PLUGIN, webapi_getNeighbors.PLUGIN,
webapi_spammer.PLUGIN, webapi_spammer.PLUGIN,
ui.PLUGIN, ui.PLUGIN,
webauth.PLUGIN,
graph.PLUGIN, graph.PLUGIN,
), ),
......
package findTransactions package findTransactionHashes
import ( import (
"net/http" "net/http"
...@@ -11,19 +11,19 @@ import ( ...@@ -11,19 +11,19 @@ import (
"github.com/labstack/echo" "github.com/labstack/echo"
) )
var PLUGIN = node.NewPlugin("WebAPI findTransactions Endpoint", node.Enabled, configure) var PLUGIN = node.NewPlugin("WebAPI findTransactionHashes Endpoint", node.Enabled, configure)
var log *logger.Logger var log *logger.Logger
func configure(plugin *node.Plugin) { func configure(plugin *node.Plugin) {
log = logger.NewLogger("API-findTransactions") log = logger.NewLogger("API-findTransactionHashes")
webapi.Server.POST("findTransactions", findTransactions) webapi.Server.POST("findTransactionHashes", findTransactionHashes)
} }
// findTransactions returns the array of transaction hashes for the // findTransactionHashes returns the array of transaction hashes for the
// given addresses (in the same order as the parameters). // given addresses (in the same order as the parameters).
// If a node doesn't have any transaction hash for a given address in its ledger, // If a node doesn't have any transaction hash for a given address in its ledger,
// the value at the index of that address is empty. // the value at the index of that address is empty.
func findTransactions(c echo.Context) error { func findTransactionHashes(c echo.Context) error {
var request Request var request Request
if err := c.Bind(&request); err != nil { if err := c.Bind(&request); err != nil {
......
package getTransactions package getTransactionObjectsByHash
import ( import (
"net/http" "net/http"
...@@ -11,19 +11,19 @@ import ( ...@@ -11,19 +11,19 @@ import (
"github.com/labstack/echo" "github.com/labstack/echo"
) )
var PLUGIN = node.NewPlugin("WebAPI getTransaction Endpoint", node.Enabled, configure) var PLUGIN = node.NewPlugin("WebAPI getTransactionObjectsByHash Endpoint", node.Enabled, configure)
var log *logger.Logger var log *logger.Logger
func configure(plugin *node.Plugin) { func configure(plugin *node.Plugin) {
log = logger.NewLogger("API-getTransactions") log = logger.NewLogger("API-getTransactionObjectsByHash")
webapi.Server.POST("getTransactions", getTransactions) webapi.Server.POST("getTransactionObjectsByHash", getTransactionObjectsByHash)
} }
// getTransactions returns the array of transactions for the // getTransactionObjectsByHash returns the array of transactions for the
// given transaction hashes (in the same order as the parameters). // given transaction hashes (in the same order as the parameters).
// If a node doesn't have the transaction for a given transaction hash in its ledger, // If a node doesn't have the transaction for a given transaction hash in its ledger,
// the value at the index of that transaction hash is empty. // the value at the index of that transaction hash is empty.
func getTransactions(c echo.Context) error { func getTransactionObjectsByHash(c echo.Context) error {
var request Request var request Request
result := []Transaction{} result := []Transaction{}
......
package getTrytes package getTransactionTrytesByHash
import ( import (
"net/http" "net/http"
...@@ -11,19 +11,19 @@ import ( ...@@ -11,19 +11,19 @@ import (
"github.com/labstack/echo" "github.com/labstack/echo"
) )
var PLUGIN = node.NewPlugin("WebAPI getTrytes Endpoint", node.Enabled, configure) var PLUGIN = node.NewPlugin("WebAPI getTransactionTrytesByHash Endpoint", node.Enabled, configure)
var log *logger.Logger var log *logger.Logger
func configure(plugin *node.Plugin) { func configure(plugin *node.Plugin) {
log = logger.NewLogger("API-getTrytes") log = logger.NewLogger("API-getTransactionTrytesByHash")
webapi.Server.GET("getTrytes", getTrytes) webapi.Server.GET("getTransactionTrytesByHash", getTransactionTrytesByHash)
} }
// getTrytes returns the array of transaction trytes for the // getTransactionTrytesByHash returns the array of transaction trytes for the
// given transaction hashes (in the same order as the parameters). // given transaction hashes (in the same order as the parameters).
// If a node doesn't have the trytes for a given transaction hash in its ledger, // If a node doesn't have the trytes for a given transaction hash in its ledger,
// the value at the index of that transaction hash is empty. // the value at the index of that transaction hash is empty.
func getTrytes(c echo.Context) error { func getTransactionTrytesByHash(c echo.Context) error {
var request Request var request Request
result := []trinary.Trytes{} result := []trinary.Trytes{}
......
package webapi
import (
flag "github.com/spf13/pflag"
)
const (
BIND_ADDRESS = "webapi.bindAddress"
)
func init() {
flag.String(BIND_ADDRESS, "0.0.0.0:8080", "the bind address for the web API")
}
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
"context" "context"
"time" "time"
"github.com/iotaledger/goshimmer/packages/parameter"
"github.com/iotaledger/goshimmer/packages/shutdown" "github.com/iotaledger/goshimmer/packages/shutdown"
"github.com/iotaledger/hive.go/daemon" "github.com/iotaledger/hive.go/daemon"
"github.com/iotaledger/hive.go/logger" "github.com/iotaledger/hive.go/logger"
...@@ -30,7 +31,7 @@ func run(plugin *node.Plugin) { ...@@ -30,7 +31,7 @@ func run(plugin *node.Plugin) {
log.Info("Starting Web Server ... done") log.Info("Starting Web Server ... done")
go func() { go func() {
if err := Server.Start(":8080"); err != nil { if err := Server.Start(parameter.NodeConfig.GetString(BIND_ADDRESS)); err != nil {
log.Info("Stopping Web Server ... done") log.Info("Stopping Web Server ... done")
} }
}() }()
......
package webauth
import (
flag "github.com/spf13/pflag"
)
const (
WEBAPI_AUTH_USERNAME = "webapi.auth.username"
WEBAPI_AUTH_PASSWORD = "webapi.auth.password"
WEBAPI_AUTH_PRIVATE_KEY = "webapi.auth.privateKey"
)
func init() {
flag.String(WEBAPI_AUTH_USERNAME, "goshimmer", "username for the webapi")
flag.String(WEBAPI_AUTH_PASSWORD, "goshimmer", "password for the webapi")
flag.String(WEBAPI_AUTH_PRIVATE_KEY, "", "private key used to sign the JWTs")
}
...@@ -2,13 +2,12 @@ package webauth ...@@ -2,13 +2,12 @@ package webauth
import ( import (
"net/http" "net/http"
"os"
"strings" "strings"
"time" "time"
"github.com/iotaledger/goshimmer/packages/shutdown" "github.com/iotaledger/goshimmer/packages/parameter"
"github.com/iotaledger/goshimmer/plugins/webapi" "github.com/iotaledger/goshimmer/plugins/webapi"
"github.com/iotaledger/hive.go/daemon" "github.com/iotaledger/hive.go/logger"
"github.com/iotaledger/hive.go/node" "github.com/iotaledger/hive.go/node"
"github.com/labstack/echo" "github.com/labstack/echo"
"github.com/labstack/echo/middleware" "github.com/labstack/echo/middleware"
...@@ -16,59 +15,60 @@ import ( ...@@ -16,59 +15,60 @@ import (
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
) )
var secret = "secret" var PLUGIN = node.NewPlugin("WebAPI Auth", node.Disabled, configure)
var log *logger.Logger
var privateKey string
func configure(plugin *node.Plugin) { func configure(plugin *node.Plugin) {
log = logger.NewLogger("WebAPI Auth")
jwtKey := os.Getenv("JWT_KEY") privateKey = parameter.NodeConfig.GetString(WEBAPI_AUTH_PRIVATE_KEY)
if jwtKey != "" { if len(privateKey) == 0 {
secret = jwtKey panic("")
} }
webapi.Server.Use(middleware.JWTWithConfig(middleware.JWTConfig{ webapi.Server.Use(middleware.JWTWithConfig(middleware.JWTConfig{
SigningKey: []byte(secret), SigningKey: []byte(privateKey),
TokenLookup: "query:token",
Skipper: func(c echo.Context) bool { Skipper: func(c echo.Context) bool {
// if strings.HasPrefix(c.Request().Host, "localhost") {
// return true
// }
if strings.HasPrefix(c.Path(), "/ui") || c.Path() == "/login" { if strings.HasPrefix(c.Path(), "/ui") || c.Path() == "/login" {
return true return true
} }
return false return false
}, },
})) }))
webapi.Server.POST("/login", Handler)
log.Info("WebAPI is now secured through JWT authentication")
}
type Request struct {
Username string `json:"username"`
Password string `json:"password"`
} }
func run(plugin *node.Plugin) { type Response struct {
daemon.BackgroundWorker("webauth", func(shutdownSignal <-chan struct{}) { Token string `json:"token"`
webapi.Server.GET("login", func(c echo.Context) error { }
username := c.FormValue("username")
password := c.FormValue("password")
uiUser := os.Getenv("UI_USER")
uiPass := os.Getenv("UI_PASS")
// Throws unauthorized error func Handler(c echo.Context) error {
if username != uiUser || password != uiPass { login := &Request{}
return echo.ErrUnauthorized if err := c.Bind(login); err != nil {
} return echo.ErrBadRequest
}
token := jwt.New(jwt.SigningMethodHS256) if login.Username != parameter.NodeConfig.GetString(WEBAPI_AUTH_USERNAME) ||
claims := token.Claims.(jwt.MapClaims) login.Password != parameter.NodeConfig.GetString(WEBAPI_AUTH_PASSWORD) {
claims["name"] = username return echo.ErrUnauthorized
claims["exp"] = time.Now().Add(time.Hour * 24 * 7).Unix() }
t, err := token.SignedString([]byte(secret)) token := jwt.New(jwt.SigningMethodHS256)
if err != nil { claims := token.Claims.(jwt.MapClaims)
return err claims["name"] = login.Username
} claims["exp"] = time.Now().Add(time.Hour * 24 * 7).Unix()
return c.JSON(http.StatusOK, map[string]string{ t, err := token.SignedString([]byte(privateKey))
"token": t, if err != nil {
}) return err
}) }
}, shutdown.ShutdownPriorityWebAPI)
}
// PLUGIN plugs the UI into the main program return c.JSON(http.StatusOK, &Response{Token: t})
var PLUGIN = node.NewPlugin("webauth", node.Disabled, configure, run) }
...@@ -5,23 +5,21 @@ import ( ...@@ -5,23 +5,21 @@ import (
"time" "time"
client "github.com/iotaledger/goshimmer/client" client "github.com/iotaledger/goshimmer/client"
"github.com/iotaledger/goshimmer/packages/errors"
"github.com/iotaledger/iota.go/trinary" "github.com/iotaledger/iota.go/trinary"
) )
func testBroadcastData(api *client.GoShimmerAPI) (trinary.Hash, error) { func testBroadcastData(api *client.GoShimmerAPI) (trinary.Hash, error) {
txnHash, err := api.BroadcastData(txnAddr, txnData) txnHash, err := api.BroadcastData(txnAddr, txnData)
if err != nil { if err != nil {
return "", errors.Wrapf(err, "Broadcast failed") return "", fmt.Errorf("broadcast failed: %w", err)
} }
return txnHash, nil return txnHash, nil
} }
func testTargetGetTransactions(api *client.GoShimmerAPI, txnHash trinary.Hash) error { func testTargetGetTransactions(api *client.GoShimmerAPI, txnHash trinary.Hash) error {
// query target node for broadcasted data // query target node for broadcasted data
_, err := api.GetTransactions([]trinary.Hash{txnHash}) if _, err := api.GetTransactionObjectsByHash([]trinary.Hash{txnHash}); err != nil {
if err != nil { return fmt.Errorf("querying the target node failed: %w", err)
return errors.Wrapf(err, "Query target failed")
} }
return nil return nil
} }
...@@ -30,11 +28,10 @@ func testNodesGetTransactions(txnHash trinary.Hash) error { ...@@ -30,11 +28,10 @@ func testNodesGetTransactions(txnHash trinary.Hash) error {
// query nodes node for broadcasted data // query nodes node for broadcasted data
for _, n := range nodes { for _, n := range nodes {
nodesApi := client.NewGoShimmerAPI(n) nodesApi := client.NewGoShimmerAPI(n)
_, err := nodesApi.GetTransactions([]trinary.Hash{txnHash}) if _, err := nodesApi.GetTransactionObjectsByHash([]trinary.Hash{txnHash}); err != nil {
if err != nil { return fmt.Errorf("querying node %s failed: %w", n, err)
return errors.Wrapf(err, "Query %s failed", n)
} }
fmt.Printf("txn found in %s\n", n) fmt.Printf("txn found in node %s\n", n)
} }
return nil return nil
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment