Skip to content

Commit

Permalink
Merge c55e1e7 into ac295d2
Browse files Browse the repository at this point in the history
  • Loading branch information
robdefeo committed Mar 8, 2020
2 parents ac295d2 + c55e1e7 commit 2862f83
Show file tree
Hide file tree
Showing 15 changed files with 294 additions and 81 deletions.
6 changes: 1 addition & 5 deletions cmd/nameservice/commands/execute.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,5 @@ package commands

// Execute run the command
func Execute() error {
root, err := rootCmd()
if err != nil {
return err
}
return root.Execute()
return rootCmd().Execute()
}
31 changes: 17 additions & 14 deletions cmd/nameservice/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,41 @@ import (

"github.com/gorilla/mux"
"github.com/mailchain/mailchain/cmd/nameservice/handler"
"github.com/mailchain/mailchain/internal/protocols"
"github.com/mailchain/mailchain/internal/protocols/ethereum"
"github.com/mailchain/mailchain/nameservice"
"github.com/mailchain/mailchain/nameservice/ens"
"github.com/spf13/cobra"
"github.com/urfave/negroni"
)

func config() (map[string]nameservice.Lookup, error) {
func addENS(router *mux.Router) error {
ethMainnet, err := ens.NewLookupService("https://mainnet.infura.io/v3/.....")
if err != nil {
return nil, err
return err
}
return map[string]nameservice.Lookup{
"ethereum/mainnet": ethMainnet,
// ...
}, nil

addItem(router, protocols.Ethereum, ethereum.Mainnet, ethMainnet)

return nil
}

func addItem(router *mux.Router, protocol, network string, service nameservice.Lookup) {
router.HandleFunc(fmt.Sprintf("/%s/%s/name", protocol, network), handler.Forward(service, protocol, network)).Methods("GET")
router.HandleFunc(fmt.Sprintf("/%s/%s/address", protocol, network), handler.Reverse(service, protocol, network)).Methods("GET")
}

// {protocol}/{network}/name/?domain-name={domain-name}
// {protocol}/{network}/address?address={address}
func rootCmd() (*cobra.Command, error) {
func rootCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "nameservice",
RunE: func(cmd *cobra.Command, args []string) error {
r := mux.NewRouter()
cfg, err := config()
if err != nil {

if err := addENS(r); err != nil {
return err
}
for k, v := range cfg {
r.HandleFunc(fmt.Sprintf("/%s/name", k), handler.Forward(v)).Methods("GET")
r.HandleFunc(fmt.Sprintf("/%s/address", k), handler.Reverse(v)).Methods("GET")
}

n := negroni.New()
n.UseHandler(r)
Expand All @@ -50,5 +53,5 @@ func rootCmd() (*cobra.Command, error) {
}
cmd.PersistentFlags().Int("port", 8080, "")

return cmd, nil
return cmd
}
11 changes: 6 additions & 5 deletions cmd/nameservice/handler/forward.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ package handler
import (
"encoding/json"
"net/http"
"strings"

"github.com/gorilla/mux"
"github.com/mailchain/mailchain/errs"
"github.com/mailchain/mailchain/internal/address"
"github.com/mailchain/mailchain/nameservice"
"github.com/pkg/errors"
)

// Forward handle forward domain lookups where an address is looked up to find a domain name.
func Forward(resolver nameservice.ForwardLookup) func(w http.ResponseWriter, r *http.Request) {
func Forward(resolver nameservice.ForwardLookup, protocol, network string) func(w http.ResponseWriter, r *http.Request) {
type response struct {
Address string `json:"address"`

Expand All @@ -24,9 +22,8 @@ func Forward(resolver nameservice.ForwardLookup) func(w http.ResponseWriter, r *
// example: 3
Status int `json:"status,omitempty"`
}

return func(w http.ResponseWriter, r *http.Request) {
protocol := strings.ToLower(mux.Vars(r)["protocol"])
network := strings.ToLower(mux.Vars(r)["network"])
if len(r.URL.Query()["domain-name"]) != 1 {
errs.JSONWriter(w, http.StatusPreconditionFailed, errors.Errorf("domain-name must be specified exactly once"))
return
Expand All @@ -37,17 +34,21 @@ func Forward(resolver nameservice.ForwardLookup) func(w http.ResponseWriter, r *
_ = json.NewEncoder(w).Encode(response{
Status: nameservice.RFC1035StatusMap[err],
})

return
}

if err != nil {
errs.JSONWriter(w, http.StatusInternalServerError, err)
return
}

encAddress, _, err := address.EncodeByProtocol(resolvedAddress, protocol)
if err != nil {
errs.JSONWriter(w, http.StatusInternalServerError, errors.WithMessage(err, "failed to encode address"))
return
}

w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(response{
Address: encAddress,
Expand Down
22 changes: 21 additions & 1 deletion cmd/nameservice/handler/forward_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ func TestForward(t *testing.T) {

type args struct {
resolver nameservice.ForwardLookup
protocol string
network string
}
tests := []struct {
name string
Expand All @@ -42,6 +44,8 @@ func TestForward(t *testing.T) {
m.EXPECT().ResolveName(gomock.Any(), "ethereum", "mainnet", "test.eth").Return(encodingtest.MustDecodeHex("5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761"), nil)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?domain-name=test.eth", nil)
Expand All @@ -64,6 +68,8 @@ func TestForward(t *testing.T) {
Return(nil, nameservice.ErrFormat)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?domain-name=test.eth", nil)
Expand All @@ -86,6 +92,8 @@ func TestForward(t *testing.T) {
Return(nil, nameservice.ErrServFail)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?domain-name=test.eth", nil)
Expand All @@ -108,6 +116,8 @@ func TestForward(t *testing.T) {
Return(nil, nameservice.ErrNXDomain)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?domain-name=test.eth", nil)
Expand All @@ -130,6 +140,8 @@ func TestForward(t *testing.T) {
Return(nil, nameservice.ErrNotImp)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?domain-name=test.eth", nil)
Expand All @@ -152,6 +164,8 @@ func TestForward(t *testing.T) {
Return(nil, nameservice.ErrRefused)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?domain-name=test.eth", nil)
Expand All @@ -172,6 +186,8 @@ func TestForward(t *testing.T) {
m.EXPECT().ResolveName(gomock.Any(), "invalid", "mainnet", "test.eth").Return(encodingtest.MustDecodeHex("5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761"), nil)
return m
}(),
"invalid",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?domain-name=test.eth", nil)
Expand All @@ -192,6 +208,8 @@ func TestForward(t *testing.T) {
m.EXPECT().ResolveName(gomock.Any(), "ethereum", "mainnet", "test.eth").Return(nil, errors.Errorf("failed"))
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?domain-name=test.eth", nil)
Expand All @@ -211,6 +229,8 @@ func TestForward(t *testing.T) {
m := nameservicetest.NewMockForwardLookup(mockCtrl)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?", nil)
Expand All @@ -228,7 +248,7 @@ func TestForward(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(Forward(tt.args.resolver))
handler := http.HandlerFunc(Forward(tt.args.resolver, tt.args.protocol, tt.args.network))

// Our handlers satisfy http.Handler, so we can call their ServeHTTP method
// directly and pass in our Request and ResponseRecorder.
Expand Down
18 changes: 10 additions & 8 deletions cmd/nameservice/handler/reverse.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package handler

import (
"encoding/hex"
"encoding/json"
"net/http"
"strings"

"github.com/gorilla/mux"
"github.com/mailchain/mailchain/errs"
"github.com/mailchain/mailchain/internal/address"
"github.com/mailchain/mailchain/nameservice"
"github.com/pkg/errors"
)

// Reverse handle forward domain lookups where a domain name is looked up to find an address.
func Reverse(resolver nameservice.ReverseLookup) func(w http.ResponseWriter, r *http.Request) {
func Reverse(resolver nameservice.ReverseLookup, protocol, network string) func(w http.ResponseWriter, r *http.Request) {
type response struct {
Name string `json:"name"`

Expand All @@ -24,27 +22,31 @@ func Reverse(resolver nameservice.ReverseLookup) func(w http.ResponseWriter, r *
// example: 3
Status int `json:"status,omitempty"`
}

return func(w http.ResponseWriter, r *http.Request) {
protocol := strings.ToLower(mux.Vars(r)["protocol"])
network := strings.ToLower(mux.Vars(r)["network"])
if len(r.URL.Query()["address"]) != 1 {
errs.JSONWriter(w, http.StatusPreconditionFailed, errors.Errorf("address must be specified exactly once"))
return
}
address, err := hex.DecodeString(strings.TrimPrefix(r.URL.Query()["address"][0], "0x"))

addr, err := address.DecodeByProtocol(r.URL.Query()["address"][0], protocol)
if err != nil {
_ = json.NewEncoder(w).Encode(response{
Status: nameservice.RFC1035StatusMap[nameservice.ErrFormat],
})

return
}
name, err := resolver.ResolveAddress(r.Context(), protocol, network, address)

name, err := resolver.ResolveAddress(r.Context(), protocol, network, addr)
if nameservice.IsRFC1035Error(err) {
_ = json.NewEncoder(w).Encode(response{
Status: nameservice.RFC1035StatusMap[err],
})

return
}

if err != nil {
errs.JSONWriter(w, http.StatusInternalServerError, err)
return
Expand Down
16 changes: 15 additions & 1 deletion cmd/nameservice/handler/reverse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ func TestReverse(t *testing.T) {

type args struct {
resolver nameservice.ReverseLookup
protocol string
network string
}
tests := []struct {
name string
Expand All @@ -42,6 +44,8 @@ func TestReverse(t *testing.T) {
m.EXPECT().ResolveAddress(gomock.Any(), "ethereum", "mainnet", encodingtest.MustDecodeHex("5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761")).Return("test.eth", nil)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?address=0x5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761", nil)
Expand All @@ -62,6 +66,8 @@ func TestReverse(t *testing.T) {
m.EXPECT().ResolveAddress(gomock.Any(), "ethereum", "mainnet", encodingtest.MustDecodeHex("5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761")).Return("", errors.Errorf("failed"))
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?address=0x5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761", nil)
Expand All @@ -82,6 +88,8 @@ func TestReverse(t *testing.T) {
m.EXPECT().ResolveAddress(gomock.Any(), "ethereum", "mainnet", encodingtest.MustDecodeHex("5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761")).Return("", nameservice.ErrNXDomain)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?address=0x5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761", nil)
Expand All @@ -102,6 +110,8 @@ func TestReverse(t *testing.T) {
m.EXPECT().ResolveAddress(gomock.Any(), "ethereum", "mainnet", encodingtest.MustDecodeHex("5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761")).Return("", nameservice.ErrFormat)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?address=0x5602ea95540bee46d03ba335eed6f49d117eab95c8ab8b71bae2cdd1e564a761", nil)
Expand All @@ -121,6 +131,8 @@ func TestReverse(t *testing.T) {
m := nameservicetest.NewMockReverseLookup(mockCtrl)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?address=0x560", nil)
Expand All @@ -140,6 +152,8 @@ func TestReverse(t *testing.T) {
m := nameservicetest.NewMockReverseLookup(mockCtrl)
return m
}(),
"ethereum",
"mainnet",
},
func() *http.Request {
req := httptest.NewRequest("GET", "/?", nil)
Expand All @@ -157,7 +171,7 @@ func TestReverse(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
// We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
rr := httptest.NewRecorder()
handler := http.HandlerFunc(Reverse(tt.args.resolver))
handler := http.HandlerFunc(Reverse(tt.args.resolver, tt.args.protocol, tt.args.network))

// Our handlers satisfy http.Handler, so we can call their ServeHTTP method
// directly and pass in our Request and ResponseRecorder.
Expand Down
2 changes: 1 addition & 1 deletion cmd/nameservice/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ import (

func main() {
if err := commands.Execute(); err != nil {
log.Fatalln(err)
log.Fatalf("%+v\n", err)
}
}

0 comments on commit 2862f83

Please sign in to comment.