Skip to content

Commit

Permalink
feat: adding custom-networks verifications
Browse files Browse the repository at this point in the history
  • Loading branch information
javip97 committed Apr 18, 2024
1 parent c87d79d commit d0c9ec9
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 101 deletions.
5 changes: 0 additions & 5 deletions .env-sample
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
VERIFIER_BACKEND_HOST=http://localhost:3010
VERIFIER_BACKEND_PORT=3010
VERIFIER_BACKEND_KEY_DIR=./keys


VERIFIER_IPFS_URL=https://gateway.pinata.cloud
VERIFIER_BACKEND_MUMBAI_SENDER_DID=did:polygonid:polygon:mumbai:2qH7TstpRRJHXNN4o49Fu9H2Qismku8hQeUxDVrjqT
VERIFIER_BACKEND_MAIN_SENDER_DID=did:polygonid:polygon:main:2q4Q7F7tM1xpwUTgWivb6TgKX3vWirsE3mqymuYjVv
VERIFIER_BACKEND_AMOY_SENDER_DID=did:polygonid:polygon:amoy:2qV9QXdhXXmN5sKjN1YueMjxgRbnJcEGK2kGpvk3cq
VERIFIER_BACKEND_RESOLVER_SETTINGS_PATH=./resolvers_settings.yaml
VERIFIER_BACKEND_CACHE_EXPIRATION=60m
69 changes: 66 additions & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
package main

import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"strconv"
"syscall"

"github.com/go-chi/chi/v5"
chiMiddleware "github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
auth "github.com/iden3/go-iden3-auth/v2"
"github.com/iden3/go-iden3-auth/v2/loaders"
"github.com/iden3/go-iden3-auth/v2/pubsignals"
"github.com/iden3/go-iden3-auth/v2/state"
core "github.com/iden3/go-iden3-core/v2"
log "github.com/sirupsen/logrus"

"github.com/0xPolygonID/verifier-backend/internal/api"
"github.com/0xPolygonID/verifier-backend/internal/config"
"github.com/0xPolygonID/verifier-backend/internal/errors"
"github.com/0xPolygonID/verifier-backend/internal/loader"
)

func main() {
ctx := context.Background()
cfg, err := config.Load()
if err != nil {
log.WithField("error", err).Error("cannot load config")
return
}

keysLoader := &loaders.FSKeyLoader{Dir: cfg.KeyDIR}

mux := chi.NewRouter()

mux.Use(
Expand All @@ -36,7 +42,21 @@ func main() {
chiMiddleware.NoCache,
)

apiServer := api.New(*cfg, keysLoader)
keysLoader := &loaders.FSKeyLoader{Dir: cfg.KeyDIR}
w3cLoader := loader.NewW3CDocumentLoader(nil, cfg.IPFSURL)
resolvers, senderDIDs, err := parseResolverSettings(ctx, cfg.ResolverSettings)
if err != nil {
log.WithField("error", err).Error("cannot parse resolver settings")
return
}

verifier, err := auth.NewVerifier(keysLoader, resolvers, auth.WithDocumentLoader(w3cLoader))
if err != nil {
log.WithFields(log.Fields{"err": err}).Error("failed to create verifier")
return
}

apiServer := api.New(*cfg, verifier, senderDIDs)
api.HandlerFromMux(api.NewStrictHandlerWithOptions(apiServer, nil,
api.StrictHTTPServerOptions{RequestErrorHandlerFunc: errors.RequestErrorHandlerFunc}), mux)
api.RegisterStatic(mux)
Expand All @@ -58,3 +78,46 @@ func main() {
<-quit
log.Info("Shutting down")
}

// parseResolverSettings parses the resolver settings from the config file
func parseResolverSettings(ctx context.Context, rs config.ResolverSettings) (map[string]pubsignals.StateResolver, map[string]string, error) {
var (
resolvers = make(map[string]pubsignals.StateResolver)
verifiersDIDs = make(map[string]string)
)

for chainName, chainSettings := range rs {
for networkName, networkSettings := range chainSettings {
prefix := fmt.Sprintf("%s:%s", chainName, networkName)
resolver := state.NewETHResolver(networkSettings.NetworkURL, networkSettings.ContractAddress)
resolvers[prefix] = resolver

if err := registerCustomDIDMethod(ctx, chainName, networkName, networkSettings); err != nil {
log.Error(ctx, "cannot register custom DID method", "err", err)
return nil, nil, err
}

verifiersDIDs[networkSettings.ChainID] = networkSettings.DID
}
}

return resolvers, verifiersDIDs, nil
}

func registerCustomDIDMethod(ctx context.Context, blockchain string, network string, resolverAttrs config.ResolverSettingsAttrs) error {
chainID, err := strconv.Atoi(resolverAttrs.ChainID)
if err != nil {
return fmt.Errorf("cannot convert chainID to int: %w", err)
}
params := core.DIDMethodNetworkParams{
Method: core.DIDMethodPolygonID,
Blockchain: core.Blockchain(blockchain),
Network: core.NetworkID(network),
NetworkFlag: resolverAttrs.NetworkFlag,
}
if err := core.RegisterDIDMethodNetwork(params, core.WithChainID(chainID)); err != nil {
log.Error(ctx, "cannot register custom DID method", "err", err, "customDID", chainID)
return err
}
return nil
}
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ require (
github.com/go-chi/cors v1.2.1
github.com/golangci/golangci-lint v1.55.1
github.com/google/uuid v1.6.0
github.com/iden3/contracts-abi/state/go/abi v1.0.1
github.com/iden3/go-circuits/v2 v2.2.0
github.com/iden3/go-iden3-auth/v2 v2.2.2
github.com/iden3/go-iden3-core/v2 v2.1.0
github.com/iden3/go-jwz/v2 v2.0.2
github.com/iden3/go-schema-processor/v2 v2.3.3
github.com/iden3/iden3comm/v2 v2.3.2
github.com/ipfs/go-ipfs-api v0.7.0
Expand All @@ -20,6 +22,7 @@ require (
github.com/oapi-codegen/runtime v1.1.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/piprate/json-gold v0.5.1-0.20230111113000-6ddbe6e6f19f
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.3
github.com/stretchr/testify v1.9.0
gopkg.in/yaml.v3 v3.0.1
Expand Down Expand Up @@ -122,9 +125,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/holiman/uint256 v1.2.4 // indirect
github.com/iden3/contracts-abi/state/go/abi v1.0.1 // indirect
github.com/iden3/go-iden3-crypto v0.0.16 // indirect
github.com/iden3/go-jwz/v2 v2.0.2 // indirect
github.com/iden3/go-merkletree-sql/v2 v2.0.6 // indirect
github.com/iden3/go-rapidsnark/prover v0.0.10 // indirect
github.com/iden3/go-rapidsnark/types v0.0.3 // indirect
Expand Down Expand Up @@ -194,7 +195,6 @@ require (
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
github.com/perimeterx/marshmallow v1.1.4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polyfloyd/go-errorlint v1.4.5 // indirect
github.com/pquerna/cachecontrol v0.2.0 // indirect
Expand Down
10 changes: 4 additions & 6 deletions internal/api/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@ var (

func TestMain(m *testing.M) {
cfg = config.Config{
Host: "http://localhost",
ApiPort: "3000",
KeyDIR: "./keys",
MumbaiSenderDID: "did:polygonid:polygon:mumbai:2qH7TstpRRJHXNN4o49Fu9H2Qismku8hQeUxDVrjqT",
MainSenderDID: "did:polygonid:polygon:main:2qH7TstpRRJHXNN4o49Fu9H2Qismku8hQeUxDVrjqT",
IPFSURL: "https://gateway.pinata.cloud",
Host: "http://localhost",
ApiPort: "3000",
KeyDIR: "./keys",
IPFSURL: "https://gateway.pinata.cloud",
ResolverSettings: config.ResolverSettings{
"polygon": {
"mumbai": {
Expand Down
98 changes: 34 additions & 64 deletions internal/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import (
"github.com/google/uuid"
"github.com/iden3/go-circuits/v2"
auth "github.com/iden3/go-iden3-auth/v2"
"github.com/iden3/go-iden3-auth/v2/loaders"
"github.com/iden3/go-iden3-auth/v2/pubsignals"
"github.com/iden3/go-iden3-auth/v2/state"
core "github.com/iden3/go-iden3-core/v2"
"github.com/iden3/go-iden3-core/v2/w3c"
"github.com/iden3/iden3comm/v2/protocol"
Expand All @@ -27,7 +25,6 @@ import (

"github.com/0xPolygonID/verifier-backend/internal/common"
"github.com/0xPolygonID/verifier-backend/internal/config"
"github.com/0xPolygonID/verifier-backend/internal/loader"
"github.com/0xPolygonID/verifier-backend/internal/models"
)

Expand All @@ -45,20 +42,22 @@ const (

// Server represents the API server
type Server struct {
keyLoader *loaders.FSKeyLoader
cfg config.Config
qrStore *QRcodeStore
cache *cache.Cache
cfg config.Config
qrStore *QRcodeStore
cache *cache.Cache
verifier *auth.Verifier
senderDIDs map[string]string
}

// New creates a new API server
func New(cfg config.Config, keyLoader *loaders.FSKeyLoader) *Server {
func New(cfg config.Config, verifier *auth.Verifier, senderDIDs map[string]string) *Server {
c := cache.New(cfg.CacheExpiration.AsDuration(), cfg.CacheExpiration.AsDuration())
return &Server{
cfg: cfg,
keyLoader: keyLoader,
qrStore: NewQRCodeStore(c),
cache: c,
cfg: cfg,
qrStore: NewQRCodeStore(c),
cache: c,
verifier: verifier,
senderDIDs: senderDIDs,
}
}

Expand Down Expand Up @@ -106,19 +105,7 @@ func (s *Server) Callback(ctx context.Context, request CallbackRequestObject) (C
}, nil
}

w3cLoader := loader.NewW3CDocumentLoader(nil, s.cfg.IPFSURL)

resolvers := s.parseResolverSettings()
verifier, err := auth.NewVerifier(s.keyLoader, resolvers, auth.WithDocumentLoader(w3cLoader))
if err != nil {
log.WithFields(log.Fields{
"sessionID": sessionID,
"err": err,
}).Error("failed to create verifier")
return nil, err
}

authRespMsg, err := verifier.FullVerify(ctx, *request.Body,
authRespMsg, err := s.verifier.FullVerify(ctx, *request.Body,
authRequest.(protocol.AuthorizationRequestMessage),
pubsignals.WithAcceptedStateTransitionDelay(stateTransitionDelay))
if err != nil {
Expand Down Expand Up @@ -172,7 +159,7 @@ func (s *Server) SignIn(_ context.Context, request SignInRequestObject) (SignInR

switch circuits.CircuitID(request.Body.Scope[0].CircuitId) {
case circuits.AtomicQuerySigV2CircuitID, circuits.AtomicQueryMTPV2CircuitID, circuits.AtomicQueryV3CircuitID:
authReq, err := getAuthRequestOffChain(request, s.cfg, sessionID)
authReq, err := s.getAuthRequestOffChain(request, sessionID)
if err != nil {
log.Error(err)
return SignIn400JSONResponse{N400JSONResponse{err.Error()}}, nil
Expand All @@ -188,7 +175,7 @@ func (s *Server) SignIn(_ context.Context, request SignInRequestObject) (SignInR
SessionID: sessionID,
}, nil
case circuits.AtomicQuerySigV2OnChainCircuitID, circuits.AtomicQueryMTPV2OnChainCircuitID, circuits.AtomicQueryV3OnChainCircuitID:
invokeReq, err := getContractInvokeRequestOnChain(request, s.cfg)
invokeReq, err := s.getContractInvokeRequestOnChain(request)
if err != nil {
log.Error(err)
return SignIn400JSONResponse{N400JSONResponse{err.Error()}}, nil
Expand Down Expand Up @@ -263,19 +250,6 @@ func writeFile(path string, mimeType string, w http.ResponseWriter) {
_, _ = w.Write(f)
}

// parseResolverSettings parses the resolver settings from the config file
func (s *Server) parseResolverSettings() map[string]pubsignals.StateResolver {
resolvers := map[string]pubsignals.StateResolver{}
for chainName, chainSettings := range s.cfg.ResolverSettings {
for networkName, networkSettings := range chainSettings {
prefix := fmt.Sprintf("%s:%s", chainName, networkName)
resolver := state.NewETHResolver(networkSettings.NetworkURL, networkSettings.ContractAddress)
resolvers[prefix] = resolver
}
}
return resolvers
}

func getAuthReqQRCode(request protocol.AuthorizationRequestMessage) QRCode {
scopes := make([]Scope, 0, len(request.Body.Scope))
for _, scope := range request.Body.Scope {
Expand Down Expand Up @@ -352,25 +326,13 @@ func validateOffChainRequest(request SignInRequestObject) error {
return fmt.Errorf("field chainId is empty expected %s or %s or %s", mumbaiNetwork, mainnetNetwork, amoyNetwork)
}

if err := validateNetWork(*request.Body.ChainID); err != nil {
return err
}

if err := validateRequestQuery(true, request.Body.Scope); err != nil {
return err
}

return nil
}

func validateNetWork(chainID string) error {
if chainID != mumbaiNetwork && chainID != mainnetNetwork && chainID != amoyNetwork {
return fmt.Errorf("field chainID value is wrong, got %s, expected %s or %s or %s", chainID, mumbaiNetwork, mainnetNetwork, amoyNetwork)
}

return nil
}

func validateRequestQuery(offChainRequest bool, scope []ScopeRequest) error {
reqIds := make(map[uint32]bool, 0)
for _, scope := range scope {
Expand Down Expand Up @@ -420,13 +382,18 @@ func validateRequestQuery(offChainRequest bool, scope []ScopeRequest) error {
return nil
}

func getAuthRequestOffChain(req SignInRequestObject, cfg config.Config, sessionID uuid.UUID) (protocol.AuthorizationRequestMessage, error) {
func (s *Server) getAuthRequestOffChain(req SignInRequestObject, sessionID uuid.UUID) (protocol.AuthorizationRequestMessage, error) {
if err := validateOffChainRequest(req); err != nil {
return protocol.AuthorizationRequestMessage{}, err
}

senderDID, err := s.getSenderDID(*req.Body.ChainID)
if err != nil {
return protocol.AuthorizationRequestMessage{}, err
}

id := uuid.NewString()
authReq := auth.CreateAuthorizationRequest(getReason(req.Body.Reason), getSenderID(*req.Body.ChainID, cfg), getUri(cfg, sessionID))
authReq := auth.CreateAuthorizationRequest(getReason(req.Body.Reason), senderDID, getUri(s.cfg, sessionID))
authReq.ID = id
authReq.ThreadID = id
authReq.To = ""
Expand Down Expand Up @@ -481,7 +448,7 @@ func checkOnChainRequest(req SignInRequestObject) error {
return nil
}

func getContractInvokeRequestOnChain(req SignInRequestObject, cfg config.Config) (protocol.ContractInvokeRequestMessage, error) {
func (s *Server) getContractInvokeRequestOnChain(req SignInRequestObject) (protocol.ContractInvokeRequestMessage, error) {
if err := checkOnChainRequest(req); err != nil {
return protocol.ContractInvokeRequestMessage{}, err
}
Expand Down Expand Up @@ -509,8 +476,13 @@ func getContractInvokeRequestOnChain(req SignInRequestObject, cfg config.Config)
ChainID: req.Body.TransactionData.ChainID,
Network: req.Body.TransactionData.Network,
}
senderDID, err := s.getSenderDID(strconv.Itoa(transactionData.ChainID))
if err != nil {
return protocol.ContractInvokeRequestMessage{}, err
}

authReq := auth.CreateContractInvokeRequest(getReason(req.Body.Reason), senderDID, transactionData, mtpProofRequests...)
id := uuid.NewString()
authReq := auth.CreateContractInvokeRequest(getReason(req.Body.Reason), getSenderID(strconv.Itoa(transactionData.ChainID), cfg), transactionData, mtpProofRequests...)
authReq.ID = id
authReq.ThreadID = id
authReq.To = ""
Expand Down Expand Up @@ -565,15 +537,13 @@ func getParams(params ScopeParams) (map[string]interface{}, error) {
return map[string]interface{}{"nullifierSessionId": nullifierSessionID.String()}, nil
}

func getSenderID(chainID string, cfg config.Config) string {
switch chainID {
case mumbaiNetwork:
return cfg.MumbaiSenderDID
case mainnetNetwork:
return cfg.MainSenderDID
default:
return cfg.AmoySenderDID
func (s *Server) getSenderDID(chainID string) (string, error) {
val, ok := s.senderDIDs[chainID]
if !ok {
return "", fmt.Errorf("sender not found for chainID %s", chainID)
}

return val, nil
}

func getUri(cfg config.Config, sessionID uuid.UUID) string {
Expand Down
Loading

0 comments on commit d0c9ec9

Please sign in to comment.