Skip to content

Commit

Permalink
DEV-1074: improve error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Toktar committed Apr 15, 2022
1 parent dc4a663 commit 1b91d7c
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 100 deletions.
9 changes: 9 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
method: cheqd
listener: 0.0.0.0:1313
path: "/1.0/identifiers/:did"
ledgerTimeout: 5s #sec
loglevel: debug

networks:
mainnet: rpc.cheqd.net:443
testnet: 159.89.208.88:443
4 changes: 0 additions & 4 deletions config.yml

This file was deleted.

33 changes: 19 additions & 14 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ go 1.17
require (
github.com/cheqd/cheqd-node v0.5.0
github.com/labstack/echo/v4 v4.7.2
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.7.1
google.golang.org/grpc v1.45.0
)

require (
Expand Down Expand Up @@ -48,15 +49,16 @@ require (
github.com/lestrrat-go/jwx v1.2.20 // indirect
github.com/lestrrat-go/option v1.0.0 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/mr-tron/base58 v1.1.0 // indirect
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multibase v0.0.3 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand All @@ -65,23 +67,22 @@ require (
github.com/prometheus/common v0.30.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.2.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.9.0 // indirect
github.com/spf13/viper v1.11.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tendermint/tendermint v0.34.15 // indirect
github.com/tendermint/tm-db v0.6.6 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12 // indirect
google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/ini.v1 v1.63.2 // indirect
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
Expand All @@ -91,15 +92,19 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/protobuf v1.5.2
github.com/labstack/gommon v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
)

replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
replace (
// Fix upstream GHSA-h395-qcrw-5vmq vulnerability.
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
)
44 changes: 44 additions & 0 deletions go.sum

Large diffs are not rendered by default.

61 changes: 17 additions & 44 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
package main

import (
"flag"
"fmt"
"net/http"
"os"

"github.com/cheqd/cheqd-did-resolver/services"
"github.com/cheqd/cheqd-did-resolver/types"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"gopkg.in/yaml.v2"
"github.com/spf13/viper"

"strings"
)

type Config struct {
Networks map[string]string `yaml:"networks"`
}

func main() {
didResolutionPath := flag.String("path", "/1.0/identifiers/:did", "URL path with DID resolution endpoint")
didResolutionPort := flag.String("port", ":1313", "The endpoint port with DID resolution")
flag.Parse()
viper.SetConfigFile("config.yaml")
err := viper.ReadInConfig()
if err != nil { // Handle errors reading the config file
panic(fmt.Errorf("Fatal error config file: %w \n", err))
}
didResolutionPath := viper.GetString("path")
didResolutionListener := viper.GetString("listener")

// Echo instance
e := echo.New()
Expand All @@ -31,57 +30,31 @@ func main() {
e.Use(middleware.Recover())

//setup
e.StdLogger.Println("get config")
config, err := getConfig("config.yml")
e.StdLogger.Println(config)
if err != nil {
e.Logger.Fatal(err)
}
networks := viper.GetStringMapString("networks")
ledgerService := services.NewLedgerService()
for network, url := range config.Networks {
for network, url := range networks {
e.StdLogger.Println(network)
ledgerService.RegisterLedger(network, url)
}
requestService := services.NewRequestService(ledgerService)

// Routes
e.GET(*didResolutionPath, func(c echo.Context) error {
e.GET(didResolutionPath, func(c echo.Context) error {
did := c.Param("did")
accept := strings.Split(c.Request().Header.Get("accept"), ";")[0]
if strings.Contains(accept, types.ResolutionJSONLDType) {
accept = types.ResolutionDIDJSONLDType
} else {
accept = types.ResolutionDIDJSONType
}
resolutionOption := map[string]string{"Accept": accept}
e.StdLogger.Println("get did")
responseBody, err := requestService.ProcessDIDRequest(did, resolutionOption)
status := http.StatusOK
if err != "" {
// todo: defined a correct status
status = http.StatusBadRequest
responseBody, err := requestService.ProcessDIDRequest(did, types.ResolutionOption{Accept: accept})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
}
c.Response().Header().Set(echo.HeaderContentType, accept)
return c.JSONBlob(status, []byte(responseBody))
return c.JSONBlob(http.StatusOK, []byte(responseBody))
})

// Start server
e.Logger.Fatal(e.Start(*didResolutionPort))
}

func getConfig(configFileName string) (Config, error) {
f, err := os.Open(configFileName)
if err != nil {
return Config{}, err
}
defer f.Close()

var cfg Config
decoder := yaml.NewDecoder(f)
err = decoder.Decode(&cfg)
if err != nil {
return Config{}, err
}

return cfg, nil
e.Logger.Fatal(e.Start(didResolutionListener))
}
34 changes: 21 additions & 13 deletions services/ledger_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package services
import (
"context"
"errors"
"flag"
"strings"
"time"

cheqd "github.com/cheqd/cheqd-node/x/cheqd/types"
cheqdUtils "github.com/cheqd/cheqd-node/x/cheqd/utils"
"github.com/spf13/viper"
"google.golang.org/grpc"
)

Expand All @@ -21,25 +20,28 @@ func NewLedgerService() LedgerService {
return ls
}

func (ls LedgerService) QueryDIDDoc(did string) (cheqd.Did, cheqd.Metadata, error) {
func (ls LedgerService) QueryDIDDoc(did string) (cheqd.Did, cheqd.Metadata, bool, error) {
isFound := true
serverAddr := ls.ledgers[getNamespace(did)]
println(serverAddr)
conn, err := openGRPCConnection(serverAddr)

if err != nil {
return cheqd.Did{}, cheqd.Metadata{}, err
isFound = false
return cheqd.Did{}, cheqd.Metadata{}, isFound, err
}

qc := cheqd.NewQueryClient(conn)
defer conn.Close()

didDocResponse, err := qc.Did(context.Background(), &cheqd.QueryGetDidRequest{Id: did})
if err != nil {
return cheqd.Did{}, cheqd.Metadata{}, err
isFound = false
return cheqd.Did{}, cheqd.Metadata{}, isFound, nil
}
println("QueryDIDDoc: received response")
println(didDocResponse)
return *didDocResponse.Did, *didDocResponse.Metadata, err
return *didDocResponse.Did, *didDocResponse.Metadata, isFound, err
}

func (ls *LedgerService) RegisterLedger(namespace string, url string) error {
Expand All @@ -53,8 +55,7 @@ func (ls *LedgerService) RegisterLedger(namespace string, url string) error {
println("Ledger node url cannot be empty")
return errors.New("Ledger node url cannot be empty")
}
ls.ledgers[namespace] = *flag.String("grpc-server-address-"+namespace, url,
"The target grpc server address in the format of host:port")
ls.ledgers[namespace] = url

println("RegisterLedger end")

Expand All @@ -66,9 +67,7 @@ func openGRPCConnection(addr string) (conn *grpc.ClientConn, err error) {
grpc.WithInsecure(),
grpc.WithBlock(),
}
// TODO: move to application setup
// TODO: move timeouts to a config
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), viper.GetDuration("ledgerTimeout"))
defer cancel()

conn, err = grpc.DialContext(ctx, addr, opts...)
Expand All @@ -83,5 +82,14 @@ func openGRPCConnection(addr string) (conn *grpc.ClientConn, err error) {
}

func getNamespace(did string) string {
return strings.SplitN(did, ":", 4)[2]
_, namespace, _, _ := cheqdUtils.TrySplitDID(did)
return namespace
}

func (ls LedgerService) GetNamespaces() []string {
keys := make([]string, 0, len(ls.ledgers))
for k, _ := range ls.ledgers {
keys = append(keys, k)
}
return keys
}
68 changes: 49 additions & 19 deletions services/request_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"fmt"

"github.com/cheqd/cheqd-did-resolver/types"
cheqdUtils "github.com/cheqd/cheqd-node/x/cheqd/utils"
"github.com/spf13/viper"
)

type RequestService struct {
Expand All @@ -21,41 +23,63 @@ func NewRequestService(ledgerService LedgerService) RequestService {
}
}

func (rs RequestService) ProcessDIDRequest(did string, params map[string]string) (string, string) {
didResolution := rs.resolve(did, types.ResolutionOption{Accept: params["Accept"]})
resolutionMetadata, err1 := json.Marshal(didResolution.ResolutionMetadata)
didDoc, err2 := rs.didDocService.MarshallDID(didResolution.Did)
metadata, err3 := rs.didDocService.MarshallProto(&didResolution.Metadata)

if err1 != nil || err2 != nil || err3 != nil {
resolutionMetadataProto := types.NewResolutionMetadata(did, params["Accept"],
types.ResolutionRepresentationNotSupported)
resolutionMetadataJson, _ := json.Marshal(resolutionMetadataProto)
return createJsonResolution("null", "null", string(resolutionMetadataJson)),
resolutionMetadataProto.ResolutionError
func (rs RequestService) ProcessDIDRequest(did string, resolutionOptions types.ResolutionOption) (string, error) {

didResolution, err := rs.resolve(did, types.ResolutionOption{resolutionOptions.Accept})
if err != nil {
return "", err
}

resolutionMetadata, err := json.Marshal(didResolution.ResolutionMetadata)
if err != nil {
return "", err
}

didDoc, err := rs.didDocService.MarshallDID(didResolution.Did)
if err != nil {
return "", err
}

metadata, err := rs.didDocService.MarshallProto(&didResolution.Metadata)
if err != nil {
return "", err
}

if didResolution.ResolutionMetadata.ResolutionError != "" {
return createJsonResolution("null", "null", string(resolutionMetadata)),
didResolution.ResolutionMetadata.ResolutionError
didDoc, metadata = "", ""
}

return createJsonResolution(didDoc, metadata, string(resolutionMetadata)), ""
return createJsonResolution(didDoc, metadata, string(resolutionMetadata)), nil

}

// https://w3c-ccg.github.io/did-resolution/#resolving
func (rs RequestService) resolve(did string, resolutionOptions types.ResolutionOption) types.DidResolution {
didDoc, metadata, err := rs.ledgerService.QueryDIDDoc(did)
func (rs RequestService) resolve(did string, resolutionOptions types.ResolutionOption) (types.DidResolution, error) {

didResolutionMetadata := types.NewResolutionMetadata(did, resolutionOptions.Accept, "")

method := viper.GetString("method")
if !cheqdUtils.IsValidDID(did, method, rs.ledgerService.GetNamespaces()) {
if didMethod, _, _, _ := cheqdUtils.TrySplitDID(did); didMethod != method {
didResolutionMetadata.ResolutionError = types.ResolutionMethodNotSupported
} else {
didResolutionMetadata.ResolutionError = types.ResolutionInvalidDID
}
return types.DidResolution{ResolutionMetadata: didResolutionMetadata}, nil
}

didDoc, metadata, isFound, err := rs.ledgerService.QueryDIDDoc(did)
if err != nil {
return types.DidResolution{}, err
}
if !isFound {
didResolutionMetadata.ResolutionError = types.ResolutionNotFound
return types.DidResolution{ResolutionMetadata: didResolutionMetadata}
return types.DidResolution{ResolutionMetadata: didResolutionMetadata}, nil
}
if didResolutionMetadata.ContentType == types.ResolutionDIDJSONLDType {
didDoc.Context = append(didDoc.Context, types.DIDSchemaJSONLD)
}
return types.DidResolution{didDoc, metadata, didResolutionMetadata}
return types.DidResolution{didDoc, metadata, didResolutionMetadata}, nil
}

// https://w3c-ccg.github.io/did-resolution/#dereferencing
Expand All @@ -68,6 +92,12 @@ func (rs RequestService) resolve(did string, resolutionOptions types.ResolutionO
// }

func createJsonResolution(didDoc string, metadata string, resolutionMetadata string) string {
if didDoc == "" {
didDoc = "null"
}
if metadata == "" {
metadata = "[]"
}
return fmt.Sprintf("{\"didDocument\" : %s,\"didDocumentMetadata\" : %s,\"didResolutionMetadata\" : %s}",
didDoc, metadata, resolutionMetadata)
}
Loading

0 comments on commit 1b91d7c

Please sign in to comment.