From 23ad9212170108e85ef8ea8bee892c53b268419a Mon Sep 17 00:00:00 2001 From: Gabe Date: Wed, 28 Sep 2022 16:36:10 -0700 Subject: [PATCH] Support key access in all services (#110) * utility wrappers * init * utilize key encryption * config updatse * temp * did svc uses keystore pt 1 * using the keystore pt 2 * temp * add storage, update manifest with some todos * merge * fix dwn tests * bad rename * pr comments --- config/compose.toml | 9 +- config/config.go | 49 +++- config/config.toml | 13 +- go.mod | 2 +- go.sum | 6 +- internal/keyaccess/dataintegrity.go | 10 +- internal/keyaccess/dataintegrity_test.go | 6 +- internal/keyaccess/jwt.go | 47 +++- internal/keyaccess/jwt_test.go | 16 +- internal/util/crypto.go | 4 +- pkg/server/router/credential_test.go | 11 +- pkg/server/router/did_test.go | 7 +- pkg/server/router/dwn_test.go | 9 +- pkg/server/router/manifest.go | 6 +- pkg/server/router/manifest_test.go | 13 +- pkg/server/router/router_test.go | 2 +- pkg/server/router/schema_test.go | 9 +- pkg/server/router/testutils_test.go | 30 ++ pkg/server/server_test.go | 339 ++++++++++++++--------- pkg/service/credential/credential.go | 12 +- pkg/service/did/did.go | 103 +++---- pkg/service/did/key.go | 39 ++- pkg/service/did/storage/bolt.go | 8 +- pkg/service/did/storage/storage.go | 3 +- pkg/service/dwn/dwn.go | 9 +- pkg/service/keystore/keystore.go | 23 ++ pkg/service/keystore/model.go | 16 +- pkg/service/keystore/storage/bolt.go | 38 ++- pkg/service/keystore/storage/storage.go | 20 +- pkg/service/manifest/manifest.go | 163 +++++------ pkg/service/manifest/storage/storage.go | 14 +- pkg/service/schema/schema.go | 15 +- pkg/service/service.go | 45 +-- 33 files changed, 695 insertions(+), 401 deletions(-) create mode 100644 pkg/server/router/testutils_test.go diff --git a/config/compose.toml b/config/compose.toml index 6597c39c4..332648e90 100644 --- a/config/compose.toml +++ b/config/compose.toml @@ -23,6 +23,10 @@ log_level = "info" storage = "bolt" # per-service configuration +[services.keystore] +name = "keystore" +password = "default-password" + [services.did] name = "did" methods = ["key"] @@ -33,6 +37,9 @@ name = "schema" [services.credential] name = "credential" +[services.manifest] +name = "manifest" + [services.dwn] name = "dwn" -dwn_endpoint = "http://localhost:4321" +dwn_endpoint = "http://localhost:4321" \ No newline at end of file diff --git a/config/config.go b/config/config.go index 37a98958b..09bd3e219 100644 --- a/config/config.go +++ b/config/config.go @@ -48,10 +48,10 @@ type ServicesConfig struct { // Embed all service-specific configs here. The order matters: from which should be instantiated first, to last + KeyStoreConfig KeyStoreServiceConfig `toml:"keystore,omitempty"` DIDConfig DIDServiceConfig `toml:"did,omitempty"` SchemaConfig SchemaServiceConfig `toml:"schema,omitempty"` CredentialConfig CredentialServiceConfig `toml:"credential,omitempty"` - KeyStoreConfig KeyStoreServiceConfig `toml:"keystore,omitempty"` ManifestConfig ManifestServiceConfig `toml:"manifest,omitempty"` DWNConfig DWNServiceConfig `toml:"dwn,omitempty"` } @@ -62,6 +62,20 @@ type BaseServiceConfig struct { Name string `toml:"name"` } +type KeyStoreServiceConfig struct { + *BaseServiceConfig + // Service key password. Used by a KDF whose key is used by a symmetric cypher for key encryption. + // The password is salted before usage. + ServiceKeyPassword string `toml:"password"` +} + +func (k *KeyStoreServiceConfig) IsEmpty() bool { + if k == nil { + return true + } + return reflect.DeepEqual(k, &KeyStoreServiceConfig{}) +} + type DIDServiceConfig struct { *BaseServiceConfig Methods []string `toml:"methods"` @@ -90,20 +104,34 @@ type CredentialServiceConfig struct { // TODO(gabe) supported key and signature types } +func (c *CredentialServiceConfig) IsEmpty() bool { + if c == nil { + return true + } + return reflect.DeepEqual(c, &CredentialServiceConfig{}) +} + type ManifestServiceConfig struct { *BaseServiceConfig } +func (m *ManifestServiceConfig) IsEmpty() bool { + if m == nil { + return true + } + return reflect.DeepEqual(m, &ManifestServiceConfig{}) +} + type DWNServiceConfig struct { *BaseServiceConfig DWNEndpoint string `toml:"dwn_endpoint"` } -type KeyStoreServiceConfig struct { - *BaseServiceConfig - // Service key password. Used by a KDF whose key is used by a symmetric cypher for key encryption. - // The password is salted before usage. - ServiceKeyPassword string +func (d *DWNServiceConfig) IsEmpty() bool { + if d == nil { + return true + } + return reflect.DeepEqual(d, &DWNServiceConfig{}) } // LoadConfig attempts to load a TOML config file from the given path, and coerce it into our object model. @@ -149,6 +177,10 @@ func LoadConfig(path string) (*SSIServiceConfig, error) { if defaultConfig { config.Services = ServicesConfig{ StorageProvider: "bolt", + KeyStoreConfig: KeyStoreServiceConfig{ + BaseServiceConfig: &BaseServiceConfig{Name: "keystore"}, + ServiceKeyPassword: "default-password", + }, DIDConfig: DIDServiceConfig{ BaseServiceConfig: &BaseServiceConfig{Name: "did"}, Methods: []string{"key"}, @@ -159,9 +191,8 @@ func LoadConfig(path string) (*SSIServiceConfig, error) { CredentialConfig: CredentialServiceConfig{ BaseServiceConfig: &BaseServiceConfig{Name: "credential"}, }, - KeyStoreConfig: KeyStoreServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "keystore"}, - ServiceKeyPassword: "default-password", + ManifestConfig: ManifestServiceConfig{ + BaseServiceConfig: &BaseServiceConfig{Name: "manifest"}, }, DWNConfig: DWNServiceConfig{ BaseServiceConfig: &BaseServiceConfig{Name: "dwn"}, diff --git a/config/config.toml b/config/config.toml index aa5031333..afd2ff38d 100644 --- a/config/config.toml +++ b/config/config.toml @@ -21,6 +21,10 @@ log_level = "debug" storage = "bolt" # per-service configuration +[services.keystore] +name = "keystore" +password = "default-password" + [services.did] name = "did" methods = ["key"] @@ -29,4 +33,11 @@ methods = ["key"] name = "schema" [services.credential] -name = "credential" \ No newline at end of file +name = "credential" + +[services.manifest] +name = "manifest" + +[services.dwn] +name = "dwn" +dwn_endpoint = "http://localhost:4321" \ No newline at end of file diff --git a/go.mod b/go.mod index c07bdbc3a..f0197d84d 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.19 require ( github.com/BurntSushi/toml v1.2.0 - github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220923181557-56fc273d1dcd + github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220921215642-f749c4d89b8b github.com/ardanlabs/conf v1.5.0 github.com/dimfeld/httptreemux/v5 v5.4.0 github.com/go-playground/locales v0.14.0 diff --git a/go.sum b/go.sum index f7ee5311a..6467abe1f 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,11 @@ github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0= github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220915152202-18c69f474901 h1:7cT1hMDiWQlsQYNP2U0mxpUjc5AxKVElcAdvTt5amnM= -github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220915152202-18c69f474901/go.mod h1:uXrbtCwqgsbZvL/zM3+DpAOuuIax9qG2aeUhZrGPCck= github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220919021815-57be087eca80 h1:1HBBtzkjsgjCYjMVWi6+785SO+Q7kSOOrA0Njw3JON0= github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220919021815-57be087eca80/go.mod h1:ZUcjj/CHvtmz48c9GapcbavlTRsN9JZ9pKdT+co/EvY= github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220920154030-cbf6b4665a6d h1:NW/9Qg2Z+Yhh6PtzgV/cFwgNz7Sgng3E25IYQiUV34c= github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220920154030-cbf6b4665a6d/go.mod h1:jkbaZT2qU+g6weOHpjPdxuHdmfOApdT8CQg41GEyZhA= -github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220923181557-56fc273d1dcd h1:BTbS7+/QsnxvVhP0LwB3JJxnT/9qHC8msEtku2JF4QY= -github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220923181557-56fc273d1dcd/go.mod h1:jkbaZT2qU+g6weOHpjPdxuHdmfOApdT8CQg41GEyZhA= +github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220921215642-f749c4d89b8b h1:0IJJPN8qBGEINcNheyMN/VztIj/Wu9OLzoaEdwfKMWM= +github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220921215642-f749c4d89b8b/go.mod h1:jkbaZT2qU+g6weOHpjPdxuHdmfOApdT8CQg41GEyZhA= github.com/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c= github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= diff --git a/internal/keyaccess/dataintegrity.go b/internal/keyaccess/dataintegrity.go index b12073879..ecbbb2ce6 100644 --- a/internal/keyaccess/dataintegrity.go +++ b/internal/keyaccess/dataintegrity.go @@ -47,7 +47,13 @@ func NewDataIntegrityKeyAccess(kid string, key gocrypto.PrivateKey) (*DataIntegr }, nil } -func (ka DataIntegrityKeyAccess) Sign(payload cryptosuite.Provable) ([]byte, error) { +// DataIntegrityJSON represents a response from a DataIntegrityKeyAccess.Sign() call represented +// as a serialized JSON object +type DataIntegrityJSON struct { + Data []byte `json:"data" validate:"required"` +} + +func (ka DataIntegrityKeyAccess) Sign(payload cryptosuite.Provable) (*DataIntegrityJSON, error) { if payload == nil { return nil, errors.New("payload cannot be nil") } @@ -58,7 +64,7 @@ func (ka DataIntegrityKeyAccess) Sign(payload cryptosuite.Provable) ([]byte, err if err != nil { return nil, errors.Wrap(err, "could not marshal signed payload") } - return signedJSONBytes, nil + return &DataIntegrityJSON{Data: signedJSONBytes}, nil } func (ka DataIntegrityKeyAccess) Verify(payload cryptosuite.Provable) error { diff --git a/internal/keyaccess/dataintegrity_test.go b/internal/keyaccess/dataintegrity_test.go index f6a8e7907..da42819a8 100644 --- a/internal/keyaccess/dataintegrity_test.go +++ b/internal/keyaccess/dataintegrity_test.go @@ -53,7 +53,7 @@ func TestDataIntegrityKeyAccessSignVerify(t *testing.T) { assert.NotEmpty(tt, signedCred) var cred credential.VerifiableCredential - err = json.Unmarshal(signedCred, &cred) + err = json.Unmarshal(signedCred.Data, &cred) assert.NoError(tt, err) // verify @@ -104,11 +104,11 @@ func TestDataIntegrityKeyAccessSignVerify(t *testing.T) { assert.NotEmpty(tt, signedPres) var pres credential.VerifiablePresentation - err = json.Unmarshal(signedPres, &pres) + err = json.Unmarshal(signedPres.Data, &pres) assert.NoError(tt, err) // verify err = ka.Verify(&pres) assert.NoError(tt, err) }) -} \ No newline at end of file +} diff --git a/internal/keyaccess/jwt.go b/internal/keyaccess/jwt.go index 807dc9fe9..bdbaa2ec5 100644 --- a/internal/keyaccess/jwt.go +++ b/internal/keyaccess/jwt.go @@ -42,44 +42,61 @@ func NewJWKKeyAccess(kid string, key gocrypto.PrivateKey) (*JWKKeyAccess, error) }, nil } -func (ka JWKKeyAccess) Sign(payload map[string]interface{}) ([]byte, error) { +// A JWKToken is a utility that wraps a string representation of a JSON Web Token. +type JWKToken struct { + Token string `json:"token" validate:"required"` +} + +func (ka JWKKeyAccess) Sign(payload map[string]interface{}) (*JWKToken, error) { if payload == nil { return nil, errors.New("payload cannot be nil") } - return ka.SignJWT(payload) + tokenBytes, err := ka.SignJWT(payload) + if err != nil { + return nil, errors.Wrap(err, "could not sign payload") + } + return &JWKToken{Token: string(tokenBytes)}, nil } -func (ka JWKKeyAccess) Verify(token string) error { - if token == "" { +func (ka JWKKeyAccess) Verify(token JWKToken) error { + if token.Token == "" { return errors.New("token cannot be empty") } - return ka.VerifyJWT(token) + return ka.VerifyJWT(token.Token) } -func (ka JWKKeyAccess) SignVerifiableCredential(credential credential.VerifiableCredential) ([]byte, error) { +func (ka JWKKeyAccess) SignVerifiableCredential(credential credential.VerifiableCredential) (*JWKToken, error) { if err := credential.IsValid(); err != nil { return nil, errors.New("cannot sign invalid credential") } - return signing.SignVerifiableCredentialJWT(ka.JWTSigner, credential) + tokenBytes, err := signing.SignVerifiableCredentialJWT(ka.JWTSigner, credential) + if err != nil { + return nil, errors.Wrap(err, "could not sign credential") + } + return &JWKToken{Token: string(tokenBytes)}, nil } -func (ka JWKKeyAccess) VerifyVerifiableCredential(token string) (*credential.VerifiableCredential, error) { - if token == "" { +func (ka JWKKeyAccess) VerifyVerifiableCredential(token JWKToken) (*credential.VerifiableCredential, error) { + if token.Token == "" { return nil, errors.New("token cannot be empty") } - return signing.VerifyVerifiableCredentialJWT(ka.JWTVerifier, token) + return signing.VerifyVerifiableCredentialJWT(ka.JWTVerifier, token.Token) } -func (ka JWKKeyAccess) SignVerifiablePresentation(presentation credential.VerifiablePresentation) ([]byte, error) { +func (ka JWKKeyAccess) SignVerifiablePresentation(presentation credential.VerifiablePresentation) (*JWKToken, error) { if err := presentation.IsValid(); err != nil { return nil, errors.New("cannot sign invalid presentation") } - return signing.SignVerifiablePresentationJWT(ka.JWTSigner, presentation) + tokenBytes, err := signing.SignVerifiablePresentationJWT(ka.JWTSigner, presentation) + if err != nil { + return nil, errors.Wrap(err, "could not sign presentation") + } + return &JWKToken{Token: string(tokenBytes)}, nil } -func (ka JWKKeyAccess) VerifyVerifiablePresentation(token string) (*credential.VerifiablePresentation, error) { - if token == "" { +func (ka JWKKeyAccess) VerifyVerifiablePresentation(token JWKToken) (*credential.VerifiablePresentation, error) { + if token.Token == "" { return nil, errors.New("token cannot be empty") } - return signing.VerifyVerifiablePresentationJWT(ka.JWTVerifier, token) + return signing.VerifyVerifiablePresentationJWT(ka.JWTVerifier, token.Token) } diff --git a/internal/keyaccess/jwt_test.go b/internal/keyaccess/jwt_test.go index 0920e0611..c1a00730a 100644 --- a/internal/keyaccess/jwt_test.go +++ b/internal/keyaccess/jwt_test.go @@ -50,11 +50,11 @@ func TestJWKKeyAccessSignVerify(t *testing.T) { data := map[string]interface{}{ "test": "test", } - tokenBytes, err := ka.Sign(data) + token, err := ka.Sign(data) assert.NoError(tt, err) - assert.NotEmpty(tt, tokenBytes) + assert.NotEmpty(tt, token) - err = ka.Verify(string(tokenBytes)) + err = ka.Verify(*token) assert.NoError(tt, err) }) @@ -79,7 +79,7 @@ func TestJWKKeyAccessSignVerify(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, ka) - err = ka.Verify("") + err = ka.Verify(JWKToken{}) assert.Error(tt, err) assert.Contains(tt, err.Error(), "token cannot be empty") }) @@ -101,7 +101,7 @@ func TestJWKKeyAccessSignVerifyCredentials(t *testing.T) { assert.NotEmpty(tt, signedCred) // verify - verifiedCred, err := ka.VerifyVerifiableCredential(string(signedCred)) + verifiedCred, err := ka.VerifyVerifiableCredential(*signedCred) assert.NoError(tt, err) assert.NotEmpty(tt, verifiedCred) @@ -136,7 +136,7 @@ func TestJWKKeyAccessSignVerifyCredentials(t *testing.T) { assert.NotEmpty(tt, ka) // verify - _, err = ka.VerifyVerifiableCredential("bad") + _, err = ka.VerifyVerifiableCredential(JWKToken{"bad"}) assert.Error(tt, err) assert.Contains(tt, err.Error(), "could not verify JWT and its signature") }) @@ -158,7 +158,7 @@ func TestJWKKeyAccessSignVerifyPresentations(t *testing.T) { assert.NotEmpty(tt, signedPres) // verify - verifiedPres, err := ka.VerifyVerifiablePresentation(string(signedPres)) + verifiedPres, err := ka.VerifyVerifiablePresentation(*signedPres) assert.NoError(tt, err) assert.NotEmpty(tt, verifiedPres) @@ -193,7 +193,7 @@ func TestJWKKeyAccessSignVerifyPresentations(t *testing.T) { assert.NotEmpty(tt, ka) // verify - _, err = ka.VerifyVerifiablePresentation("bad") + _, err = ka.VerifyVerifiablePresentation(JWKToken{"bad"}) assert.Error(tt, err) assert.Contains(tt, err.Error(), "could not verify JWT and its signature") }) diff --git a/internal/util/crypto.go b/internal/util/crypto.go index 9ecdc2128..d53cd2b43 100644 --- a/internal/util/crypto.go +++ b/internal/util/crypto.go @@ -57,11 +57,11 @@ func XChaCha20Poly1305Decrypt(key, data []byte) ([]byte, error) { nonce, ciphertext := data[:aead.NonceSize()], data[aead.NonceSize():] // Decrypt the message and check it wasn't tampered with. - decyrpted, err := aead.Open(nil, nonce, ciphertext, nil) + decrypted, err := aead.Open(nil, nonce, ciphertext, nil) if err != nil { return nil, errors.Wrap(err, "could not decrypt data") } - return decyrpted, nil + return decrypted, nil } // Argon2KeyGen returns an encoded string generation of a key generated using the go crypto argon2 impl diff --git a/pkg/server/router/credential_test.go b/pkg/server/router/credential_test.go index e7aef24d3..81dc1dde7 100644 --- a/pkg/server/router/credential_test.go +++ b/pkg/server/router/credential_test.go @@ -2,16 +2,18 @@ package router import ( "fmt" + "os" + "testing" + "time" + credsdk "github.com/TBD54566975/ssi-sdk/credential" "github.com/goccy/go-json" "github.com/stretchr/testify/assert" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/pkg/service/credential" "github.com/tbd54566975/ssi-service/pkg/service/framework" "github.com/tbd54566975/ssi-service/pkg/storage" - "os" - "testing" - "time" ) func TestCredentialRouter(t *testing.T) { @@ -40,7 +42,8 @@ func TestCredentialRouter(t *testing.T) { assert.NotEmpty(tt, bolt) serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential"}} - credService, err := credential.NewCredentialService(serviceConfig, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credService, err := credential.NewCredentialService(serviceConfig, bolt, keyStoreService) assert.NoError(tt, err) assert.NotEmpty(tt, credService) diff --git a/pkg/server/router/did_test.go b/pkg/server/router/did_test.go index 6313b465a..33c51220e 100644 --- a/pkg/server/router/did_test.go +++ b/pkg/server/router/did_test.go @@ -35,12 +35,13 @@ func TestDIDRouter(t *testing.T) { }) t.Run("DID Service Test", func(tt *testing.T) { - bolt, err := storage.NewBoltDB() + db, err := storage.NewBoltDB() assert.NoError(tt, err) - assert.NotEmpty(tt, bolt) + assert.NotEmpty(tt, db) + keyStoreService := testKeyStoreService(tt, db) serviceConfig := config.DIDServiceConfig{Methods: []string{string(did.KeyMethod)}} - didService, err := did.NewDIDService(serviceConfig, bolt) + didService, err := did.NewDIDService(serviceConfig, db, keyStoreService) assert.NoError(tt, err) assert.NotEmpty(tt, didService) diff --git a/pkg/server/router/dwn_test.go b/pkg/server/router/dwn_test.go index 44e1ef472..95ce3e9e6 100644 --- a/pkg/server/router/dwn_test.go +++ b/pkg/server/router/dwn_test.go @@ -1,13 +1,15 @@ package router import ( + "os" + "testing" + "github.com/stretchr/testify/assert" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/pkg/service/dwn" "github.com/tbd54566975/ssi-service/pkg/service/framework" "github.com/tbd54566975/ssi-service/pkg/storage" - "os" - "testing" ) func TestDWNRouter(t *testing.T) { @@ -36,7 +38,8 @@ func TestDWNRouter(t *testing.T) { assert.NotEmpty(tt, bolt) serviceConfig := config.DWNServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "dwn"}} - dwnService, err := dwn.NewDWNService(serviceConfig, bolt) + keyStore := testKeyStoreService(t, bolt) + dwnService, err := dwn.NewDWNService(serviceConfig, bolt, keyStore) assert.NoError(tt, err) assert.NotEmpty(tt, dwnService) diff --git a/pkg/server/router/manifest.go b/pkg/server/router/manifest.go index c8ab63137..39ba8b4ea 100644 --- a/pkg/server/router/manifest.go +++ b/pkg/server/router/manifest.go @@ -3,10 +3,12 @@ package router import ( "context" "fmt" + "net/http" + "github.com/TBD54566975/ssi-sdk/credential" manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest" + "github.com/tbd54566975/ssi-service/pkg/service/manifest" - "net/http" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -214,7 +216,7 @@ func (mr ManifestRouter) SubmitApplication(ctx context.Context, w http.ResponseW } req := request.ToServiceRequest() - submitApplicationResponse, err := mr.service.SubmitApplication(req) + submitApplicationResponse, err := mr.service.ProcessApplicationSubmission(req) if err != nil { errMsg := "could not submit application" logrus.WithError(err).Error(errMsg) diff --git a/pkg/server/router/manifest_test.go b/pkg/server/router/manifest_test.go index c936bde69..0ec97ddff 100644 --- a/pkg/server/router/manifest_test.go +++ b/pkg/server/router/manifest_test.go @@ -1,17 +1,19 @@ package router import ( + "os" + "testing" + "github.com/TBD54566975/ssi-sdk/credential/exchange" manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest" "github.com/TBD54566975/ssi-sdk/crypto" "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/pkg/service/framework" "github.com/tbd54566975/ssi-service/pkg/service/manifest" "github.com/tbd54566975/ssi-service/pkg/storage" - "os" - "testing" ) func TestManifestRouter(t *testing.T) { @@ -40,7 +42,9 @@ func TestManifestRouter(t *testing.T) { assert.NotEmpty(tt, bolt) serviceConfig := config.ManifestServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "manifest"}} - manifestService, err := manifest.NewManifestService(serviceConfig, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + testCredentialService := testCredentialService(tt, bolt, keyStoreService) + manifestService, err := manifest.NewManifestService(serviceConfig, bolt, keyStoreService, testCredentialService) assert.NoError(tt, err) assert.NotEmpty(tt, manifestService) @@ -59,7 +63,7 @@ func TestManifestRouter(t *testing.T) { // good application request createApplicationRequest := getValidApplicationRequest(createdManifest.Manifest.ID, createManifestRequest.Manifest.PresentationDefinition.InputDescriptors[0].ID) - createdApplication, err := manifestService.SubmitApplication(createApplicationRequest) + createdApplication, err := manifestService.ProcessApplicationSubmission(createApplicationRequest) assert.NoError(tt, err) assert.NotEmpty(tt, createdManifest) assert.NotEmpty(tt, createdApplication.Response.ID) @@ -111,7 +115,6 @@ func getValidManifestRequest() manifest.CreateManifestRequest { } func getValidApplicationRequest(manifestID string, submissionDescriptorId string) manifest.SubmitApplicationRequest { - createApplication := manifestsdk.CredentialApplication{ ID: uuid.New().String(), SpecVersion: "https://identity.foundation/credential-manifest/spec/v1.0.0/", diff --git a/pkg/server/router/router_test.go b/pkg/server/router/router_test.go index 7af4d714b..4bbf129a5 100644 --- a/pkg/server/router/router_test.go +++ b/pkg/server/router/router_test.go @@ -21,10 +21,10 @@ func (s *testService) Status() framework.Status { func (s *testService) Config() config.ServicesConfig { return config.ServicesConfig{ StorageProvider: "bolt", + KeyStoreConfig: config.KeyStoreServiceConfig{ServiceKeyPassword: "test-password"}, DIDConfig: config.DIDServiceConfig{Methods: []string{string(did.KeyMethod)}}, SchemaConfig: config.SchemaServiceConfig{}, CredentialConfig: config.CredentialServiceConfig{}, - KeyStoreConfig: config.KeyStoreServiceConfig{}, ManifestConfig: config.ManifestServiceConfig{}, } } diff --git a/pkg/server/router/schema_test.go b/pkg/server/router/schema_test.go index 4c7151e39..4a199492e 100644 --- a/pkg/server/router/schema_test.go +++ b/pkg/server/router/schema_test.go @@ -1,13 +1,15 @@ package router import ( + "os" + "testing" + "github.com/stretchr/testify/assert" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/pkg/service/framework" "github.com/tbd54566975/ssi-service/pkg/service/schema" "github.com/tbd54566975/ssi-service/pkg/storage" - "os" - "testing" ) func TestSchemaRouter(t *testing.T) { @@ -37,7 +39,8 @@ func TestSchemaRouter(t *testing.T) { assert.NotEmpty(tt, bolt) serviceConfig := config.SchemaServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "schema"}} - schemaService, err := schema.NewSchemaService(serviceConfig, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + schemaService, err := schema.NewSchemaService(serviceConfig, bolt, keyStoreService) assert.NoError(tt, err) assert.NotEmpty(tt, schemaService) diff --git a/pkg/server/router/testutils_test.go b/pkg/server/router/testutils_test.go new file mode 100644 index 000000000..b6da1c030 --- /dev/null +++ b/pkg/server/router/testutils_test.go @@ -0,0 +1,30 @@ +package router + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/tbd54566975/ssi-service/config" + "github.com/tbd54566975/ssi-service/pkg/service/credential" + "github.com/tbd54566975/ssi-service/pkg/service/keystore" + "github.com/tbd54566975/ssi-service/pkg/storage" +) + +func testKeyStoreService(t *testing.T, db *storage.BoltDB) *keystore.Service { + serviceConfig := config.KeyStoreServiceConfig{ServiceKeyPassword: "test-password"} + // create a keystore service + keystoreService, err := keystore.NewKeyStoreService(serviceConfig, db) + require.NoError(t, err) + require.NotEmpty(t, keystoreService) + return keystoreService +} + +func testCredentialService(t *testing.T, db *storage.BoltDB, keyStore *keystore.Service) *credential.Service { + serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential"}} + // create a credential service + credentialService, err := credential.NewCredentialService(serviceConfig, db, keyStore) + require.NoError(t, err) + require.NotEmpty(t, credentialService) + return credentialService +} diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index f2d367b55..95eee283d 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -4,9 +4,6 @@ import ( "bytes" "context" "fmt" - "github.com/TBD54566975/ssi-sdk/credential/exchange" - "github.com/tbd54566975/ssi-service/pkg/service/dwn" - "io" "net/http" "net/http/httptest" @@ -14,6 +11,10 @@ import ( "testing" "time" + "github.com/TBD54566975/ssi-sdk/credential/exchange" + + "github.com/tbd54566975/ssi-service/pkg/service/dwn" + credsdk "github.com/TBD54566975/ssi-sdk/credential" manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest" "github.com/TBD54566975/ssi-sdk/crypto" @@ -61,7 +62,6 @@ func TestHealthCheckAPI(t *testing.T) { assert.NoError(t, err) assert.Equal(t, router.HealthOK, resp.Status) - } func TestReadinessAPI(t *testing.T) { @@ -104,7 +104,8 @@ func TestDIDAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - didService := newDIDService(tt, bolt) + _, keyStoreService := newKeyStore(tt, bolt) + didService := testDIDRouter(tt, bolt, keyStoreService) // get DID methods req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/dids", nil) @@ -131,7 +132,8 @@ func TestDIDAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - didService := newDIDService(tt, bolt) + _, keyStoreService := newKeyStore(tt, bolt) + didService := testDIDRouter(tt, bolt, keyStoreService) // create DID by method - key - missing body req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/dids/key", nil) @@ -179,7 +181,8 @@ func TestDIDAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - didService := newDIDService(tt, bolt) + _, keyStore := newKeyStore(tt, bolt) + didService := testDIDRouter(tt, bolt, keyStore) // get DID by method req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/dids/bad/worse", nil) @@ -238,20 +241,6 @@ func TestDIDAPI(t *testing.T) { }) } -func newDIDService(t *testing.T, bolt *storage.BoltDB) *router.DIDRouter { - serviceConfig := config.DIDServiceConfig{Methods: []string{string(did.KeyMethod)}} - didService, err := did.NewDIDService(serviceConfig, bolt) - require.NoError(t, err) - require.NotEmpty(t, didService) - - // create router for service - didRouter, err := router.NewDIDRouter(didService) - require.NoError(t, err) - require.NotEmpty(t, didRouter) - - return didRouter -} - func TestSchemaAPI(t *testing.T) { t.Run("Test Create Schema", func(tt *testing.T) { bolt, err := storage.NewBoltDB() @@ -262,7 +251,8 @@ func TestSchemaAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - schemaService := newSchemaService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + schemaService := testSchemaRouter(tt, bolt, keyStoreService) simpleSchema := map[string]interface{}{ "type": "object", @@ -309,7 +299,8 @@ func TestSchemaAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - schemaService := newSchemaService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + schemaService := testSchemaRouter(tt, bolt, keyStoreService) // get schema that doesn't exist w := httptest.NewRecorder() @@ -395,19 +386,6 @@ func TestSchemaAPI(t *testing.T) { }) } -func newSchemaService(t *testing.T, bolt *storage.BoltDB) *router.SchemaRouter { - schemaService, err := schema.NewSchemaService(config.SchemaServiceConfig{}, bolt) - require.NoError(t, err) - require.NotEmpty(t, schemaService) - - // create router for service - schemaRouter, err := router.NewSchemaRouter(schemaService) - require.NoError(t, err) - require.NotEmpty(t, schemaRouter) - - return schemaRouter -} - func TestCredentialAPI(t *testing.T) { t.Run("Test Create Credential", func(tt *testing.T) { bolt, err := storage.NewBoltDB() @@ -418,7 +396,8 @@ func TestCredentialAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - credService := newCredentialService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credService := testCredentialRouter(tt, bolt, keyStoreService) // missing required field: data badCredRequest := router.CreateCredentialRequest{ @@ -469,7 +448,8 @@ func TestCredentialAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - credService := newCredentialService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credService := testCredentialRouter(tt, bolt, keyStoreService) w := httptest.NewRecorder() @@ -530,7 +510,8 @@ func TestCredentialAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - credService := newCredentialService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credService := testCredentialRouter(tt, bolt, keyStoreService) w := httptest.NewRecorder() @@ -579,7 +560,8 @@ func TestCredentialAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - credService := newCredentialService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credService := testCredentialRouter(tt, bolt, keyStoreService) w := httptest.NewRecorder() @@ -627,7 +609,8 @@ func TestCredentialAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - credService := newCredentialService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credService := testCredentialRouter(tt, bolt, keyStoreService) w := httptest.NewRecorder() @@ -673,7 +656,8 @@ func TestCredentialAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - credService := newCredentialService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credService := testCredentialRouter(tt, bolt, keyStoreService) createCredRequest := router.CreateCredentialRequest{ Issuer: "did:abc:123", @@ -724,19 +708,6 @@ func TestCredentialAPI(t *testing.T) { }) } -func newCredentialService(t *testing.T, bolt *storage.BoltDB) *router.CredentialRouter { - credentialService, err := credential.NewCredentialService(config.CredentialServiceConfig{}, bolt) - require.NoError(t, err) - require.NotEmpty(t, credentialService) - - // create router for service - credentialRouter, err := router.NewCredentialRouter(credentialService) - require.NoError(t, err) - require.NotEmpty(t, credentialRouter) - - return credentialRouter -} - func TestManifestAPI(t *testing.T) { t.Run("Test Create Manifest", func(tt *testing.T) { bolt, err := storage.NewBoltDB() @@ -747,7 +718,9 @@ func TestManifestAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - manifestService := newManifestService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credentialService := testCredentialService(tt, bolt, keyStoreService) + manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService) // missing required field: Manifest badManifestRequest := router.CreateManifestRequest{} @@ -756,7 +729,7 @@ func TestManifestAPI(t *testing.T) { req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", badRequestValue) w := httptest.NewRecorder() - err = manifestService.CreateManifest(newRequestContext(), w, req) + err = manifestRouter.CreateManifest(newRequestContext(), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), "invalid create manifest request") @@ -768,7 +741,7 @@ func TestManifestAPI(t *testing.T) { requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) - err = manifestService.CreateManifest(newRequestContext(), w, req) + err = manifestRouter.CreateManifest(newRequestContext(), w, req) assert.NoError(tt, err) var resp router.CreateManifestResponse @@ -788,13 +761,15 @@ func TestManifestAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - manifestService := newManifestService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credentialService := testCredentialService(tt, bolt, keyStoreService) + manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService) w := httptest.NewRecorder() // get a manifest that doesn't exit req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/bad", nil) - err = manifestService.GetManifest(newRequestContext(), w, req) + err = manifestRouter.GetManifest(newRequestContext(), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), "cannot get manifest without ID parameter") @@ -803,7 +778,7 @@ func TestManifestAPI(t *testing.T) { // get a manifest with an invalid id parameter req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/bad", nil) - err = manifestService.GetManifest(newRequestContextWithParams(map[string]string{"id": "bad"}), w, req) + err = manifestRouter.GetManifest(newRequestContextWithParams(map[string]string{"id": "bad"}), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), "could not get manifest with id: bad") @@ -815,7 +790,7 @@ func TestManifestAPI(t *testing.T) { requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) - err = manifestService.CreateManifest(newRequestContext(), w, req) + err = manifestRouter.CreateManifest(newRequestContext(), w, req) assert.NoError(tt, err) var resp router.CreateManifestResponse @@ -824,7 +799,7 @@ func TestManifestAPI(t *testing.T) { // get manifest by id req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/%s", resp.Manifest.ID), nil) - err = manifestService.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req) + err = manifestRouter.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req) assert.NoError(tt, err) var getManifestResp router.GetManifestResponse @@ -843,7 +818,9 @@ func TestManifestAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - manifestService := newManifestService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credentialService := testCredentialService(tt, bolt, keyStoreService) + manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService) w := httptest.NewRecorder() @@ -852,7 +829,7 @@ func TestManifestAPI(t *testing.T) { requestValue := newRequestValue(tt, createManifestRequest) req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) - err = manifestService.CreateManifest(newRequestContext(), w, req) + err = manifestRouter.CreateManifest(newRequestContext(), w, req) assert.NoError(tt, err) var resp router.CreateManifestResponse @@ -861,7 +838,7 @@ func TestManifestAPI(t *testing.T) { // get manifest by id req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests"), nil) - err = manifestService.GetManifests(newRequestContext(), w, req) + err = manifestRouter.GetManifests(newRequestContext(), w, req) assert.NoError(tt, err) var getManifestsResp router.GetManifestsResponse @@ -881,7 +858,9 @@ func TestManifestAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - manifestService := newManifestService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credentialService := testCredentialService(tt, bolt, keyStoreService) + manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService) // good request createManifestRequest := getValidManifestRequest() @@ -889,7 +868,7 @@ func TestManifestAPI(t *testing.T) { requestValue := newRequestValue(tt, createManifestRequest) req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) w := httptest.NewRecorder() - err = manifestService.CreateManifest(newRequestContext(), w, req) + err = manifestRouter.CreateManifest(newRequestContext(), w, req) assert.NoError(tt, err) var resp router.CreateManifestResponse @@ -900,7 +879,7 @@ func TestManifestAPI(t *testing.T) { // get credential by id req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/%s", resp.Manifest.ID), nil) - err = manifestService.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req) + err = manifestRouter.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req) assert.NoError(tt, err) var getManifestResp router.GetCredentialResponse @@ -913,14 +892,14 @@ func TestManifestAPI(t *testing.T) { // delete it req = httptest.NewRequest(http.MethodDelete, fmt.Sprintf("https://ssi-service.com/v1/manifests/%s", resp.Manifest.ID), nil) - err = manifestService.DeleteManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req) + err = manifestRouter.DeleteManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req) assert.NoError(tt, err) w.Flush() // get it back req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/%s", resp.Manifest.ID), nil) - err = manifestService.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req) + err = manifestRouter.GetManifest(newRequestContextWithParams(map[string]string{"id": resp.Manifest.ID}), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), fmt.Sprintf("could not get manifest with id: %s", resp.Manifest.ID)) }) @@ -934,7 +913,9 @@ func TestManifestAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - manifestService := newManifestService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credentialService := testCredentialService(tt, bolt, keyStoreService) + manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService) // missing required field: Application badManifestRequest := router.SubmitApplicationRequest{ @@ -945,7 +926,7 @@ func TestManifestAPI(t *testing.T) { req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", badRequestValue) w := httptest.NewRecorder() - err = manifestService.SubmitApplication(newRequestContext(), w, req) + err = manifestRouter.SubmitApplication(newRequestContext(), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), "invalid submit application request") @@ -957,7 +938,7 @@ func TestManifestAPI(t *testing.T) { requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) - err = manifestService.CreateManifest(newRequestContext(), w, req) + err = manifestRouter.CreateManifest(newRequestContext(), w, req) assert.NoError(tt, err) var resp router.CreateManifestResponse @@ -972,7 +953,7 @@ func TestManifestAPI(t *testing.T) { applicationRequestValue := newRequestValue(tt, createApplicationRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue) - err = manifestService.SubmitApplication(newRequestContext(), w, req) + err = manifestRouter.SubmitApplication(newRequestContext(), w, req) var appResp router.SubmitApplicationResponse err = json.NewDecoder(w.Body).Decode(&appResp) @@ -992,13 +973,14 @@ func TestManifestAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - manifestService := newManifestService(tt, bolt) - + keyStoreService := testKeyStoreService(tt, bolt) + credentialService := testCredentialService(tt, bolt, keyStoreService) + manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService) w := httptest.NewRecorder() // get a application that doesn't exit req := httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications/bad", nil) - err = manifestService.GetApplication(newRequestContext(), w, req) + err = manifestRouter.GetApplication(newRequestContext(), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), "cannot get application without ID parameter") @@ -1010,7 +992,7 @@ func TestManifestAPI(t *testing.T) { requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) - err = manifestService.CreateManifest(newRequestContext(), w, req) + err = manifestRouter.CreateManifest(newRequestContext(), w, req) assert.NoError(tt, err) var resp router.CreateManifestResponse @@ -1022,7 +1004,7 @@ func TestManifestAPI(t *testing.T) { applicationRequestValue := newRequestValue(tt, createApplicationRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue) - err = manifestService.SubmitApplication(newRequestContext(), w, req) + err = manifestRouter.SubmitApplication(newRequestContext(), w, req) var appResp router.SubmitApplicationResponse err = json.NewDecoder(w.Body).Decode(&appResp) @@ -1030,7 +1012,7 @@ func TestManifestAPI(t *testing.T) { // get response by id req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/responses/%s", appResp.Response.ID), nil) - err = manifestService.GetResponse(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req) + err = manifestRouter.GetResponse(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req) assert.NoError(tt, err) var getResponseResponse router.GetResponseResponse @@ -1041,7 +1023,7 @@ func TestManifestAPI(t *testing.T) { // get all responses req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/responses", nil) - err = manifestService.GetResponses(newRequestContext(), w, req) + err = manifestRouter.GetResponses(newRequestContext(), w, req) var getResponsesResp router.GetResponsesResponse err = json.NewDecoder(w.Body).Decode(&getResponsesResp) @@ -1052,7 +1034,7 @@ func TestManifestAPI(t *testing.T) { // get all applications req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue) - err = manifestService.GetApplications(newRequestContext(), w, req) + err = manifestRouter.GetApplications(newRequestContext(), w, req) var getApplicationsResp router.GetApplicationsResponse err = json.NewDecoder(w.Body).Decode(&getApplicationsResp) @@ -1063,7 +1045,7 @@ func TestManifestAPI(t *testing.T) { // get application by id req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationsResp.Applications[0].ID), nil) - err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req) + err = manifestRouter.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req) assert.NoError(tt, err) var getApplicationResponse router.GetApplicationResponse @@ -1082,7 +1064,9 @@ func TestManifestAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - manifestService := newManifestService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + credentialService := testCredentialService(tt, bolt, keyStoreService) + manifestRouter := testManifestRouter(tt, bolt, keyStoreService, credentialService) // good manifest request createManifestRequest := getValidManifestRequest() @@ -1090,7 +1074,7 @@ func TestManifestAPI(t *testing.T) { requestValue := newRequestValue(tt, createManifestRequest) req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) w := httptest.NewRecorder() - err = manifestService.CreateManifest(newRequestContext(), w, req) + err = manifestRouter.CreateManifest(newRequestContext(), w, req) assert.NoError(tt, err) var resp router.CreateManifestResponse @@ -1102,7 +1086,7 @@ func TestManifestAPI(t *testing.T) { applicationRequestValue := newRequestValue(tt, createApplicationRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue) - err = manifestService.SubmitApplication(newRequestContext(), w, req) + err = manifestRouter.SubmitApplication(newRequestContext(), w, req) var appResp router.SubmitApplicationResponse err = json.NewDecoder(w.Body).Decode(&appResp) @@ -1110,7 +1094,7 @@ func TestManifestAPI(t *testing.T) { // get all applications req = httptest.NewRequest(http.MethodGet, "https://ssi-service.com/v1/manifests/applications", applicationRequestValue) - err = manifestService.GetApplications(newRequestContext(), w, req) + err = manifestRouter.GetApplications(newRequestContext(), w, req) var getApplicationsResp router.GetApplicationsResponse err = json.NewDecoder(w.Body).Decode(&getApplicationsResp) @@ -1121,7 +1105,7 @@ func TestManifestAPI(t *testing.T) { // get the application req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationsResp.Applications[0].ID), nil) - err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req) + err = manifestRouter.GetApplication(newRequestContextWithParams(map[string]string{"id": getApplicationsResp.Applications[0].ID}), w, req) assert.NoError(tt, err) var getApplicationResp router.GetApplicationResponse @@ -1132,32 +1116,19 @@ func TestManifestAPI(t *testing.T) { // delete the application req = httptest.NewRequest(http.MethodDelete, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", getApplicationResp.Application.ID), nil) - err = manifestService.DeleteApplication(newRequestContextWithParams(map[string]string{"id": getApplicationResp.Application.ID}), w, req) + err = manifestRouter.DeleteApplication(newRequestContextWithParams(map[string]string{"id": getApplicationResp.Application.ID}), w, req) assert.NoError(tt, err) w.Flush() // get it back req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/manifests/applications/%s", appResp.Response.ID), nil) - err = manifestService.GetApplication(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req) + err = manifestRouter.GetApplication(newRequestContextWithParams(map[string]string{"id": appResp.Response.ID}), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), fmt.Sprintf("could not get application with id: %s", appResp.Response.ID)) }) } -func newManifestService(t *testing.T, bolt *storage.BoltDB) *router.ManifestRouter { - manifestService, err := manifest.NewManifestService(config.ManifestServiceConfig{}, bolt) - require.NoError(t, err) - require.NotEmpty(t, manifestService) - - // create router for service - manifestRouter, err := router.NewManifestRouter(manifestService) - require.NoError(t, err) - require.NotEmpty(t, manifestRouter) - - return manifestRouter -} - func TestDWNAPI(t *testing.T) { t.Run("Test DWN Publish Manifest", func(tt *testing.T) { bolt, err := storage.NewBoltDB() @@ -1168,9 +1139,10 @@ func TestDWNAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - dwnService := newDWNService(tt, bolt) - - manifestService := newManifestService(tt, bolt) + keyStoreService := testKeyStoreService(tt, bolt) + dwnService := testDWNRouter(tt, bolt, keyStoreService) + credentialService := testCredentialService(tt, bolt, keyStoreService) + manifestService := testManifestRouter(tt, bolt, keyStoreService, credentialService) w := httptest.NewRecorder() @@ -1197,18 +1169,6 @@ func TestDWNAPI(t *testing.T) { assert.ErrorContains(tt, err, "unsupported protocol scheme") }) } -func newDWNService(t *testing.T, bolt *storage.BoltDB) *router.DWNRouter { - dwnService, err := dwn.NewDWNService(config.DWNServiceConfig{DWNEndpoint: "test-endpoint"}, bolt) - require.NoError(t, err) - require.NotEmpty(t, dwnService) - - // create router for service - dwnRouter, err := router.NewDWNRouter(dwnService) - require.NoError(t, err) - require.NotEmpty(t, dwnRouter) - - return dwnRouter -} func TestKeyStoreAPI(t *testing.T) { t.Run("Test Store Key", func(tt *testing.T) { @@ -1220,7 +1180,7 @@ func TestKeyStoreAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - keyStoreService := newKeyStoreService(tt, bolt) + keyStoreRouter, _ := newKeyStore(tt, bolt) w := httptest.NewRecorder() // bad key type @@ -1232,7 +1192,7 @@ func TestKeyStoreAPI(t *testing.T) { } badRequestValue := newRequestValue(tt, badKeyStoreRequest) req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/keys", badRequestValue) - err = keyStoreService.StoreKey(newRequestContext(), w, req) + err = keyStoreRouter.StoreKey(newRequestContext(), w, req) assert.Error(tt, err) assert.Contains(tt, err.Error(), "could not store key: test-kid, unsupported key type: bad") @@ -1256,7 +1216,7 @@ func TestKeyStoreAPI(t *testing.T) { } requestValue := newRequestValue(tt, storeKeyRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/keys", requestValue) - err = keyStoreService.StoreKey(newRequestContext(), w, req) + err = keyStoreRouter.StoreKey(newRequestContext(), w, req) assert.NoError(tt, err) }) @@ -1269,7 +1229,7 @@ func TestKeyStoreAPI(t *testing.T) { _ = os.Remove(storage.DBFile) }) - keyStoreService := newKeyStoreService(tt, bolt) + keyStoreService, _ := newKeyStore(tt, bolt) w := httptest.NewRecorder() // store a valid key @@ -1309,20 +1269,6 @@ func TestKeyStoreAPI(t *testing.T) { }) } -func newKeyStoreService(t *testing.T, bolt *storage.BoltDB) *router.KeyStoreRouter { - serviceConfig := config.KeyStoreServiceConfig{ServiceKeyPassword: "test-password"} - keyStoreService, err := keystore.NewKeyStoreService(serviceConfig, bolt) - require.NoError(t, err) - require.NotEmpty(t, keyStoreService) - - // create router for service - keyStoreRouter, err := router.NewKeyStoreRouter(keyStoreService) - require.NoError(t, err) - require.NotEmpty(t, keyStoreRouter) - - return keyStoreRouter -} - func newRequestValue(t *testing.T, data interface{}) io.Reader { dataBytes, err := json.Marshal(data) require.NoError(t, err) @@ -1393,7 +1339,6 @@ func getValidManifestRequest() manifest.CreateManifestRequest { } func getValidApplicationRequest(manifestID string, submissionDescriptorId string) manifest.SubmitApplicationRequest { - createApplication := manifestsdk.CredentialApplication{ ID: uuid.New().String(), SpecVersion: "https://identity.foundation/credential-manifest/spec/v1.0.0/", @@ -1421,3 +1366,121 @@ func getValidApplicationRequest(manifestID string, submissionDescriptorId string return createApplicationRequest } + +func newKeyStore(t *testing.T, bolt *storage.BoltDB) (*router.KeyStoreRouter, *keystore.Service) { + keyStoreService := testKeyStoreService(t, bolt) + + // create router for service + keyStoreRouter, err := router.NewKeyStoreRouter(keyStoreService) + require.NoError(t, err) + require.NotEmpty(t, keyStoreRouter) + + return keyStoreRouter, keyStoreService +} + +func testKeyStoreService(t *testing.T, db *storage.BoltDB) *keystore.Service { + serviceConfig := config.KeyStoreServiceConfig{ + BaseServiceConfig: &config.BaseServiceConfig{Name: "test-keystore"}, + ServiceKeyPassword: "test-password", + } + + // create a keystore service + keystoreService, err := keystore.NewKeyStoreService(serviceConfig, db) + require.NoError(t, err) + require.NotEmpty(t, keystoreService) + return keystoreService +} + +func testDIDService(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *did.Service { + serviceConfig := config.DIDServiceConfig{ + BaseServiceConfig: &config.BaseServiceConfig{Name: "test-did"}, + Methods: []string{"key"}, + } + + // create a did service + didService, err := did.NewDIDService(serviceConfig, bolt, keyStore) + require.NoError(t, err) + require.NotEmpty(t, didService) + return didService +} + +func testDIDRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *router.DIDRouter { + didService := testDIDService(t, bolt, keyStore) + + // create router for service + didRouter, err := router.NewDIDRouter(didService) + require.NoError(t, err) + require.NotEmpty(t, didRouter) + return didRouter +} + +func testSchemaService(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *schema.Service { + schemaService, err := schema.NewSchemaService(config.SchemaServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "test-schema"}}, bolt, keyStore) + require.NoError(t, err) + require.NotEmpty(t, schemaService) + return schemaService +} + +func testSchemaRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *router.SchemaRouter { + schemaService := testSchemaService(t, bolt, keyStore) + + // create router for service + schemaRouter, err := router.NewSchemaRouter(schemaService) + require.NoError(t, err) + require.NotEmpty(t, schemaRouter) + return schemaRouter +} + +func testCredentialService(t *testing.T, db *storage.BoltDB, keyStore *keystore.Service) *credential.Service { + serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential"}} + + // create a credential service + credentialService, err := credential.NewCredentialService(serviceConfig, db, keyStore) + require.NoError(t, err) + require.NotEmpty(t, credentialService) + return credentialService +} + +func testCredentialRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *router.CredentialRouter { + credentialService := testCredentialService(t, bolt, keyStore) + + // create router for service + credentialRouter, err := router.NewCredentialRouter(credentialService) + require.NoError(t, err) + require.NotEmpty(t, credentialRouter) + + return credentialRouter +} + +func testManifestService(t *testing.T, db *storage.BoltDB, keyStore *keystore.Service, credential *credential.Service) *manifest.Service { + serviceConfig := config.ManifestServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "manifest"}} + // create a manifest service + manifestService, err := manifest.NewManifestService(serviceConfig, db, keyStore, credential) + require.NoError(t, err) + require.NotEmpty(t, manifestService) + return manifestService +} + +func testManifestRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service, credential *credential.Service) *router.ManifestRouter { + manifestService := testManifestService(t, bolt, keyStore, credential) + + // create router for service + manifestRouter, err := router.NewManifestRouter(manifestService) + require.NoError(t, err) + require.NotEmpty(t, manifestRouter) + + return manifestRouter +} + +func testDWNRouter(t *testing.T, bolt *storage.BoltDB, keyStore *keystore.Service) *router.DWNRouter { + dwnService, err := dwn.NewDWNService(config.DWNServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "test-dwn"}, DWNEndpoint: "test-endpoint"}, bolt, keyStore) + require.NoError(t, err) + require.NotEmpty(t, dwnService) + + // create router for service + dwnRouter, err := router.NewDWNRouter(dwnService) + require.NoError(t, err) + require.NotEmpty(t, dwnRouter) + + return dwnRouter +} diff --git a/pkg/service/credential/credential.go b/pkg/service/credential/credential.go index 70c4847c6..9da063f6a 100644 --- a/pkg/service/credential/credential.go +++ b/pkg/service/credential/credential.go @@ -11,12 +11,16 @@ import ( "github.com/tbd54566975/ssi-service/internal/util" credstorage "github.com/tbd54566975/ssi-service/pkg/service/credential/storage" "github.com/tbd54566975/ssi-service/pkg/service/framework" + "github.com/tbd54566975/ssi-service/pkg/service/keystore" "github.com/tbd54566975/ssi-service/pkg/storage" ) type Service struct { storage credstorage.Storage config config.CredentialServiceConfig + + // external dependencies + keyStore *keystore.Service } func (s Service) Type() framework.Type { @@ -37,15 +41,16 @@ func (s Service) Config() config.CredentialServiceConfig { return s.config } -func NewCredentialService(config config.CredentialServiceConfig, s storage.ServiceStorage) (*Service, error) { +func NewCredentialService(config config.CredentialServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) { credentialStorage, err := credstorage.NewCredentialStorage(s) if err != nil { errMsg := "could not instantiate storage for the credential service" return nil, util.LoggingErrorMsg(err, errMsg) } return &Service{ - storage: credentialStorage, - config: config, + storage: credentialStorage, + config: config, + keyStore: keyStore, }, nil } @@ -63,7 +68,6 @@ func (s Service) CreateCredential(request CreateCredentialRequest) (*CreateCrede // check if there's a conflict with subject ID if id, ok := request.Data[credential.VerifiableCredentialIDProperty]; ok && id != request.Subject { errMsg := fmt.Sprintf("cannot set subject<%s>, data already contains a different ID value: %s", request.Subject, id) - logrus.Error(errMsg) return nil, util.LoggingNewError(errMsg) } diff --git a/pkg/service/did/did.go b/pkg/service/did/did.go index 0c4595122..449732fa6 100644 --- a/pkg/service/did/did.go +++ b/pkg/service/did/did.go @@ -2,11 +2,14 @@ package did import ( "fmt" + "github.com/pkg/errors" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/internal/util" didstorage "github.com/tbd54566975/ssi-service/pkg/service/did/storage" "github.com/tbd54566975/ssi-service/pkg/service/framework" + "github.com/tbd54566975/ssi-service/pkg/service/keystore" "github.com/tbd54566975/ssi-service/pkg/storage" ) @@ -21,14 +24,59 @@ type Service struct { handlers map[Method]MethodHandler storage didstorage.Storage config config.DIDServiceConfig + + // external dependencies + keyStore *keystore.Service } -func (s Service) Type() framework.Type { +// MethodHandler describes the functionality of *all* possible DID service, regardless of method +type MethodHandler interface { + CreateDID(request CreateDIDRequest) (*CreateDIDResponse, error) + GetDID(request GetDIDRequest) (*GetDIDResponse, error) +} + +func NewDIDService(config config.DIDServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) { + didStorage, err := didstorage.NewDIDStorage(s) + if err != nil { + return nil, errors.Wrap(err, "could not instantiate DID storage for the DID service") + } + svc := Service{ + storage: didStorage, + handlers: make(map[Method]MethodHandler), + keyStore: keyStore, + } + + // instantiate all handlers for DID methods + for _, m := range config.Methods { + if err := svc.instantiateHandlerForMethod(Method(m)); err != nil { + return nil, errors.Wrap(err, "could not instantiate DID service") + } + } + return &svc, nil +} + +func (s *Service) instantiateHandlerForMethod(method Method) error { + switch method { + case KeyMethod: + handler, err := newKeyDIDHandler(s.storage, s.keyStore) + if err != nil { + err := fmt.Errorf("could not instnatiate did:%s handler", KeyMethod) + return util.LoggingError(err) + } + s.handlers[method] = handler + default: + err := fmt.Errorf("unsupported DID method: %s", method) + return util.LoggingError(err) + } + return nil +} + +func (s *Service) Type() framework.Type { return framework.DID } // Status is a self-reporting status for the DID service. -func (s Service) Status() framework.Status { +func (s *Service) Status() framework.Status { if s.storage == nil || len(s.handlers) == 0 { return framework.Status{ Status: framework.StatusNotReady, @@ -38,11 +86,11 @@ func (s Service) Status() framework.Status { return framework.Status{Status: framework.StatusReady} } -func (s Service) Config() config.DIDServiceConfig { +func (s *Service) Config() config.DIDServiceConfig { return s.config } -func (s Service) GetSupportedMethods() GetSupportedMethodsResponse { +func (s *Service) GetSupportedMethods() GetSupportedMethodsResponse { var methods []Method for method := range s.handlers { methods = append(methods, method) @@ -50,7 +98,7 @@ func (s Service) GetSupportedMethods() GetSupportedMethodsResponse { return GetSupportedMethodsResponse{Methods: methods} } -func (s Service) CreateDIDByMethod(request CreateDIDRequest) (*CreateDIDResponse, error) { +func (s *Service) CreateDIDByMethod(request CreateDIDRequest) (*CreateDIDResponse, error) { handler, err := s.getHandler(request.Method) if err != nil { errMsg := fmt.Sprintf("could not get handler for method<%s>", request.Method) @@ -59,7 +107,7 @@ func (s Service) CreateDIDByMethod(request CreateDIDRequest) (*CreateDIDResponse return handler.CreateDID(request) } -func (s Service) GetDIDByMethod(request GetDIDRequest) (*GetDIDResponse, error) { +func (s *Service) GetDIDByMethod(request GetDIDRequest) (*GetDIDResponse, error) { handler, err := s.getHandler(request.Method) if err != nil { errMsg := fmt.Sprintf("could not get handler for method<%s>", request.Method) @@ -68,7 +116,7 @@ func (s Service) GetDIDByMethod(request GetDIDRequest) (*GetDIDResponse, error) return handler.GetDID(request) } -func (s Service) getHandler(method Method) (MethodHandler, error) { +func (s *Service) getHandler(method Method) (MethodHandler, error) { handler, ok := s.handlers[method] if !ok { err := fmt.Errorf("could not get handler for DID method: %s", method) @@ -76,44 +124,3 @@ func (s Service) getHandler(method Method) (MethodHandler, error) { } return handler, nil } - -// MethodHandler describes the functionality of *all* possible DID service, regardless of method -type MethodHandler interface { - CreateDID(request CreateDIDRequest) (*CreateDIDResponse, error) - GetDID(request GetDIDRequest) (*GetDIDResponse, error) -} - -func NewDIDService(config config.DIDServiceConfig, s storage.ServiceStorage) (*Service, error) { - didStorage, err := didstorage.NewDIDStorage(s) - if err != nil { - return nil, errors.Wrap(err, "could not instantiate DID storage for the DID service") - } - svc := Service{ - storage: didStorage, - handlers: make(map[Method]MethodHandler), - } - - // instantiate all handlers for DID methods - for _, m := range config.Methods { - if err := svc.instantiateHandlerForMethod(Method(m)); err != nil { - return nil, errors.Wrap(err, "could not instantiate DID service") - } - } - return &svc, nil -} - -func (s *Service) instantiateHandlerForMethod(method Method) error { - switch method { - case KeyMethod: - handler, err := newKeyDIDHandler(s.storage) - if err != nil { - err := fmt.Errorf("could not instnatiate did:%s handler", KeyMethod) - return util.LoggingError(err) - } - s.handlers[method] = handler - default: - err := fmt.Errorf("unsupported DID method: %s", method) - return util.LoggingError(err) - } - return nil -} diff --git a/pkg/service/did/key.go b/pkg/service/did/key.go index 3d4a384e9..822a55774 100644 --- a/pkg/service/did/key.go +++ b/pkg/service/did/key.go @@ -10,14 +10,16 @@ import ( "github.com/sirupsen/logrus" "github.com/tbd54566975/ssi-service/pkg/service/did/storage" + "github.com/tbd54566975/ssi-service/pkg/service/keystore" ) -func newKeyDIDHandler(s storage.Storage) (MethodHandler, error) { - return &keyDIDHandler{storage: s}, nil +func newKeyDIDHandler(s storage.Storage, ks *keystore.Service) (MethodHandler, error) { + return &keyDIDHandler{storage: s, keyStore: ks}, nil } type keyDIDHandler struct { - storage storage.Storage + storage storage.Storage + keyStore *keystore.Service } func (h *keyDIDHandler) CreateDID(request CreateDIDRequest) (*CreateDIDResponse, error) { @@ -29,10 +31,6 @@ func (h *keyDIDHandler) CreateDID(request CreateDIDRequest) (*CreateDIDResponse, if err != nil { return nil, errors.Wrap(err, "could not create did:key") } - privKeyBase58, err := privateKeyToBase58(privKey) - if err != nil { - return nil, errors.Wrap(err, "could not encode private key as base58") - } // expand it to the full doc for storage expanded, err := doc.Expand() @@ -40,18 +38,37 @@ func (h *keyDIDHandler) CreateDID(request CreateDIDRequest) (*CreateDIDResponse, return nil, errors.Wrap(err, "error generating did:key document") } - // store it + // store metadata in DID storage + id := doc.ToString() storedDID := storage.StoredDID{ - DID: *expanded, - PrivateKeyBase58: privKeyBase58, + ID: id, + DID: *expanded, } if err := h.storage.StoreDID(storedDID); err != nil { return nil, errors.Wrap(err, "could not store did:key value") } + // convert to a serialized format for return to the client + privKeyBase58, err := privateKeyToBase58(privKey) + if err != nil { + return nil, errors.Wrap(err, "could not encode private key as base58") + } + + // store private key in key storage + keyStoreRequest := keystore.StoreKeyRequest{ + ID: id, + Type: request.KeyType, + Controller: id, + Key: privKey, + } + + if err := h.keyStore.StoreKey(keyStoreRequest); err != nil { + return nil, errors.Wrap(err, "could not store did:key private key") + } + return &CreateDIDResponse{ DID: storedDID.DID, - PrivateKey: storedDID.PrivateKeyBase58, + PrivateKey: privKeyBase58, }, nil } diff --git a/pkg/service/did/storage/bolt.go b/pkg/service/did/storage/bolt.go index 779cd68ac..df2b9b159 100644 --- a/pkg/service/did/storage/bolt.go +++ b/pkg/service/did/storage/bolt.go @@ -2,8 +2,10 @@ package storage import ( "fmt" + "github.com/goccy/go-json" "github.com/pkg/errors" + "github.com/tbd54566975/ssi-service/internal/util" "github.com/tbd54566975/ssi-service/pkg/storage" ) @@ -31,8 +33,8 @@ func NewBoltDIDStorage(db *storage.BoltDB) (*BoltDIDStorage, error) { } func (b BoltDIDStorage) StoreDID(did StoredDID) error { - couldNotStoreDIDErr := fmt.Sprintf("could not store DID: %s", did.DID.ID) - namespace, err := getNamespaceForDID(did.DID.ID) + couldNotStoreDIDErr := fmt.Sprintf("could not store DID: %s", did.ID) + namespace, err := getNamespaceForDID(did.ID) if err != nil { return util.LoggingErrorMsg(err, couldNotStoreDIDErr) } @@ -40,7 +42,7 @@ func (b BoltDIDStorage) StoreDID(did StoredDID) error { if err != nil { return util.LoggingErrorMsg(err, couldNotStoreDIDErr) } - return b.db.Write(namespace, did.DID.ID, didBytes) + return b.db.Write(namespace, did.ID, didBytes) } func (b BoltDIDStorage) GetDID(id string) (*StoredDID, error) { diff --git a/pkg/service/did/storage/storage.go b/pkg/service/did/storage/storage.go index 804aeae1e..038bdfcf2 100644 --- a/pkg/service/did/storage/storage.go +++ b/pkg/service/did/storage/storage.go @@ -10,9 +10,8 @@ import ( ) type StoredDID struct { + ID string `json:"id"` DID did.DIDDocument `json:"did"` - // TODO(gabe) split out key storage into a key store service encrypted with a service encryption key - PrivateKeyBase58 string `json:"privateKeyBase58"` } type Storage interface { diff --git a/pkg/service/dwn/dwn.go b/pkg/service/dwn/dwn.go index de11e230a..f3bcec849 100644 --- a/pkg/service/dwn/dwn.go +++ b/pkg/service/dwn/dwn.go @@ -2,10 +2,13 @@ package dwn import ( "fmt" + "github.com/sirupsen/logrus" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/internal/util" "github.com/tbd54566975/ssi-service/pkg/service/framework" + "github.com/tbd54566975/ssi-service/pkg/service/keystore" manifeststorage "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage" "github.com/tbd54566975/ssi-service/pkg/storage" ) @@ -13,6 +16,9 @@ import ( type Service struct { config config.DWNServiceConfig manifestStorage manifeststorage.Storage + + // external dependencies + keyStore *keystore.Service } func (s Service) Type() framework.Type { @@ -34,7 +40,7 @@ func (s Service) Config() config.DWNServiceConfig { return s.config } -func NewDWNService(config config.DWNServiceConfig, s storage.ServiceStorage) (*Service, error) { +func NewDWNService(config config.DWNServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) { manifestStorage, err := manifeststorage.NewManifestStorage(s) if err != nil { errMsg := "could not instantiate manifestStorage for the dwn service" @@ -44,6 +50,7 @@ func NewDWNService(config config.DWNServiceConfig, s storage.ServiceStorage) (*S return &Service{ config: config, manifestStorage: manifestStorage, + keyStore: keyStore, }, nil } diff --git a/pkg/service/keystore/keystore.go b/pkg/service/keystore/keystore.go index ac9145b24..77b7f72cd 100644 --- a/pkg/service/keystore/keystore.go +++ b/pkg/service/keystore/keystore.go @@ -85,6 +85,29 @@ func (s Service) StoreKey(request StoreKeyRequest) error { return nil } +func (s Service) GetKey(request GetKeyRequest) (*GetKeyResponse, error) { + + logrus.Debugf("getting key: %+v", request) + + id := request.ID + gotKey, err := s.storage.GetKey(id) + if err != nil { + err := errors.Wrapf(err, "could not get key for key: %s", id) + return nil, util.LoggingError(err) + } + if gotKey == nil { + err := errors.Wrapf(err, "key with id<%s> could not be found", id) + return nil, util.LoggingError(err) + } + return &GetKeyResponse{ + ID: gotKey.ID, + Type: gotKey.KeyType, + Controller: gotKey.Controller, + Key: gotKey.Key, + CreatedAt: gotKey.CreatedAt, + }, nil +} + func (s Service) GetKeyDetails(request GetKeyDetailsRequest) (*GetKeyDetailsResponse, error) { logrus.Debugf("getting key: %+v", request) diff --git a/pkg/service/keystore/model.go b/pkg/service/keystore/model.go index 2f4afac00..25c47ff72 100644 --- a/pkg/service/keystore/model.go +++ b/pkg/service/keystore/model.go @@ -1,6 +1,8 @@ package keystore import ( + gocrypto "crypto" + "github.com/TBD54566975/ssi-sdk/crypto" ) @@ -8,7 +10,19 @@ type StoreKeyRequest struct { ID string Type crypto.KeyType Controller string - Key []byte + Key gocrypto.PrivateKey +} + +type GetKeyRequest struct { + ID string +} + +type GetKeyResponse struct { + ID string + Type crypto.KeyType + Controller string + CreatedAt string + Key gocrypto.PrivateKey } type GetKeyDetailsRequest struct { diff --git a/pkg/service/keystore/storage/bolt.go b/pkg/service/keystore/storage/bolt.go index dd4e61ca0..af6379c7f 100644 --- a/pkg/service/keystore/storage/bolt.go +++ b/pkg/service/keystore/storage/bolt.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/goccy/go-json" + "github.com/mr-tron/base58" "github.com/pkg/errors" "github.com/tbd54566975/ssi-service/internal/util" @@ -17,7 +18,8 @@ const ( ) type BoltKeyStoreStorage struct { - db *storage.BoltDB + db *storage.BoltDB + serviceKey []byte } func NewBoltKeyStoreStorage(db *storage.BoltDB, key ServiceKey) (*BoltKeyStoreStorage, error) { @@ -25,7 +27,11 @@ func NewBoltKeyStoreStorage(db *storage.BoltDB, key ServiceKey) (*BoltKeyStoreSt return nil, errors.New("bolt db reference is nil") } - bolt := &BoltKeyStoreStorage{db: db} + keyBytes, err := base58.Decode(key.Base58Key) + if err != nil { + return nil, errors.Wrap(err, "could not decode service key") + } + bolt := &BoltKeyStoreStorage{db: db, serviceKey: keyBytes} // first, store the service key if err := bolt.storeServiceKey(key); err != nil { @@ -69,10 +75,17 @@ func (b BoltKeyStoreStorage) StoreKey(key StoredKey) error { errMsg := fmt.Sprintf("could not store key: %s", id) return util.LoggingErrorMsg(err, errMsg) } - return b.db.Write(namespace, id, keyBytes) + + // encrypt key before storing + encryptedKey, err := util.XChaCha20Poly1305Encrypt(b.serviceKey, keyBytes) + if err != nil { + return errors.Wrapf(err, "could not encrypt key: %s", key.ID) + } + + return b.db.Write(namespace, id, encryptedKey) } -func (b BoltKeyStoreStorage) GetKeyDetails(id string) (*KeyDetails, error) { +func (b BoltKeyStoreStorage) GetKey(id string) (*StoredKey, error) { storedKeyBytes, err := b.db.Read(namespace, id) if err != nil { errMsg := fmt.Sprintf("could not get key details for key: %s", id) @@ -82,11 +95,26 @@ func (b BoltKeyStoreStorage) GetKeyDetails(id string) (*KeyDetails, error) { err := fmt.Errorf("could not find key details for key: %s", id) return nil, util.LoggingError(err) } + + // decrypt key before unmarshaling + decryptedKey, err := util.XChaCha20Poly1305Decrypt(b.serviceKey, storedKeyBytes) + if err != nil { + return nil, errors.Wrapf(err, "could not decrypt key: %s", id) + } + var stored StoredKey - if err := json.Unmarshal(storedKeyBytes, &stored); err != nil { + if err := json.Unmarshal(decryptedKey, &stored); err != nil { errMsg := fmt.Sprintf("could not unmarshal stored key: %s", id) return nil, util.LoggingErrorMsg(err, errMsg) } + return &stored, nil +} + +func (b BoltKeyStoreStorage) GetKeyDetails(id string) (*KeyDetails, error) { + stored, err := b.GetKey(id) + if err != nil { + return nil, errors.Wrapf(err, "could not get key details for key: %s", id) + } return &KeyDetails{ ID: stored.ID, Controller: stored.Controller, diff --git a/pkg/service/keystore/storage/storage.go b/pkg/service/keystore/storage/storage.go index 67799c13c..226bd0ba6 100644 --- a/pkg/service/keystore/storage/storage.go +++ b/pkg/service/keystore/storage/storage.go @@ -1,6 +1,7 @@ package storage import ( + gocrypto "crypto" "fmt" "github.com/TBD54566975/ssi-sdk/crypto" @@ -11,11 +12,11 @@ import ( // StoredKey represents a common data model to store data on all key types type StoredKey struct { - ID string `json:"id"` - Controller string `json:"controller"` - KeyType crypto.KeyType `json:"keyType"` - Key []byte `json:"key"` - CreatedAt string `json:"createdAt"` + ID string `json:"id"` + Controller string `json:"controller"` + KeyType crypto.KeyType `json:"keyType"` + Key gocrypto.PrivateKey `json:"key"` + CreatedAt string `json:"createdAt"` } // KeyDetails represents a common data model to get information about a key, without revealing the key itself @@ -27,12 +28,13 @@ type KeyDetails struct { } type ServiceKey struct { - Key string - Salt string + Base58Key string + Base58Salt string } type Storage interface { StoreKey(key StoredKey) error + GetKey(id string) (*StoredKey, error) GetKeyDetails(id string) (*KeyDetails, error) } @@ -45,8 +47,8 @@ func NewKeyStoreStorage(s storage.ServiceStorage, serviceKey, serviceKeySalt str return nil, util.LoggingNewError(errMsg) } boltStorage, err := NewBoltKeyStoreStorage(gotBolt, ServiceKey{ - Key: serviceKey, - Salt: serviceKeySalt, + Base58Key: serviceKey, + Base58Salt: serviceKeySalt, }) if err != nil { return nil, util.LoggingErrorMsg(err, "could not instantiate key store bolt storage") diff --git a/pkg/service/manifest/manifest.go b/pkg/service/manifest/manifest.go index 5be797fba..e06dfcbf5 100644 --- a/pkg/service/manifest/manifest.go +++ b/pkg/service/manifest/manifest.go @@ -2,22 +2,28 @@ package manifest import ( "fmt" - "github.com/TBD54566975/ssi-sdk/credential" + + credsdk "github.com/TBD54566975/ssi-sdk/credential" + "github.com/TBD54566975/ssi-sdk/credential/exchange" "github.com/TBD54566975/ssi-sdk/credential/manifest" "github.com/sirupsen/logrus" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/internal/util" - credentialstorage "github.com/tbd54566975/ssi-service/pkg/service/credential/storage" + "github.com/tbd54566975/ssi-service/pkg/service/credential" "github.com/tbd54566975/ssi-service/pkg/service/framework" + "github.com/tbd54566975/ssi-service/pkg/service/keystore" manifeststorage "github.com/tbd54566975/ssi-service/pkg/service/manifest/storage" "github.com/tbd54566975/ssi-service/pkg/storage" - "time" ) type Service struct { - manifestStorage manifeststorage.Storage - credentialStorage credentialstorage.Storage - config config.ManifestServiceConfig + manifestStorage manifeststorage.Storage + config config.ManifestServiceConfig + + // external dependencies + credential *credential.Service + keyStore *keystore.Service } func (s Service) Type() framework.Type { @@ -28,14 +34,7 @@ func (s Service) Status() framework.Status { if s.manifestStorage == nil { return framework.Status{ Status: framework.StatusNotReady, - Message: "no manifestStorage", - } - } - - if s.credentialStorage == nil { - return framework.Status{ - Status: framework.StatusNotReady, - Message: "no credentialStorage", + Message: "no manifest storage", } } @@ -46,48 +45,41 @@ func (s Service) Config() config.ManifestServiceConfig { return s.config } -func NewManifestService(config config.ManifestServiceConfig, s storage.ServiceStorage) (*Service, error) { +func NewManifestService(config config.ManifestServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service, credential *credential.Service) (*Service, error) { manifestStorage, err := manifeststorage.NewManifestStorage(s) if err != nil { errMsg := "could not instantiate manifestStorage for the manifest service" return nil, util.LoggingErrorMsg(err, errMsg) } - - credentialStorage, err := credentialstorage.NewCredentialStorage(s) - if err != nil { - errMsg := "could not instantiate credentialStorage for the manifest service" - return nil, util.LoggingErrorMsg(err, errMsg) - } return &Service{ - manifestStorage: manifestStorage, - credentialStorage: credentialStorage, - config: config, + manifestStorage: manifestStorage, + config: config, + keyStore: keyStore, + credential: credential, }, nil } func (s Service) CreateManifest(request CreateManifestRequest) (*CreateManifestResponse, error) { logrus.Debugf("creating manifest: %+v", request) - mfst := request.Manifest - if err := mfst.IsValid(); err != nil { - errMsg := "manifest is not valid" - return nil, util.LoggingErrorMsg(err, errMsg) + m := request.Manifest + if err := m.IsValid(); err != nil { + return nil, util.LoggingErrorMsg(err, "manifest is not valid") } // store the manifest storageRequest := manifeststorage.StoredManifest{ - ID: mfst.ID, - Manifest: mfst, - Issuer: mfst.Issuer.ID, + ID: m.ID, + Manifest: m, + Issuer: m.Issuer.ID, } if err := s.manifestStorage.StoreManifest(storageRequest); err != nil { - errMsg := "could not store manifest" - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not store manifest") } // return the result - response := CreateManifestResponse{Manifest: mfst} + response := CreateManifestResponse{Manifest: m} return &response, nil } @@ -109,13 +101,12 @@ func (s Service) GetManifests() (*GetManifestsResponse, error) { gotManifests, err := s.manifestStorage.GetManifests() if err != nil { - errMsg := fmt.Sprintf("could not get manifests(s)") - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not get manifests(s)") } var manifests []manifest.CredentialManifest - for _, manifest := range gotManifests { - manifests = append(manifests, manifest.Manifest) + for _, m := range gotManifests { + manifests = append(manifests, m.Manifest) } response := GetManifestsResponse{Manifests: manifests} return &response, nil @@ -154,12 +145,11 @@ func isValidApplication(gotManifest *manifeststorage.StoredManifest, application return nil } -func (s Service) SubmitApplication(request SubmitApplicationRequest) (*SubmitApplicationResponse, error) { +func (s Service) ProcessApplicationSubmission(request SubmitApplicationRequest) (*SubmitApplicationResponse, error) { credApp := request.Application if err := credApp.IsValid(); err != nil { - errMsg := "application is not valid" - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "application is not valid") } gotManifest, err := s.manifestStorage.GetManifest(credApp.ManifestID) @@ -169,8 +159,7 @@ func (s Service) SubmitApplication(request SubmitApplicationRequest) (*SubmitApp // validate if err := isValidApplication(gotManifest, credApp); err != nil { - errMsg := fmt.Sprintf("could not validate application") - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not validate application") } // store the application @@ -186,59 +175,57 @@ func (s Service) SubmitApplication(request SubmitApplicationRequest) (*SubmitApp } // build the credential response + // TODO(gabe) need to check if this can be fulfilled and conditionally return success/denial responseBuilder := manifest.NewCredentialResponseBuilder(request.Application.ManifestID) - responseBuilder.SetApplicationID(credApp.ID) - responseBuilder.SetFulfillment(credApp.PresentationSubmission.DescriptorMap) - - credRes, err := responseBuilder.Build() - if err != nil { - errMsg := "could not build response" - return nil, util.LoggingErrorMsg(err, errMsg) + if err := responseBuilder.SetApplicationID(credApp.ID); err != nil { + return nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set application id") } - // store the response - responseStorageRequest := manifeststorage.StoredResponse{ - ID: credRes.ID, - Response: *credRes, - ManifestID: request.Application.ManifestID, - } - - var creds []credential.VerifiableCredential + var creds []credsdk.VerifiableCredential for _, od := range gotManifest.Manifest.OutputDescriptors { - - if err := s.manifestStorage.StoreResponse(responseStorageRequest); err != nil { - errMsg := "could not store response" - return nil, util.LoggingErrorMsg(err, errMsg) + credentialRequest := credential.CreateCredentialRequest{ + Issuer: gotManifest.Manifest.Issuer.ID, + Subject: request.RequesterDID, + JSONSchema: od.Schema, + // TODO(gabe) need to add in data here to match the request + schema + Data: map[string]interface{}{}, } - credentialBuilder := credential.NewVerifiableCredentialBuilder() - credentialBuilder.SetIssuer(gotManifest.Manifest.Issuer.ID) - credentialBuilder.SetCredentialSubject(map[string]interface{}{ - "id": request.RequesterDID, - }) - credentialBuilder.SetIssuanceDate(time.Now().Format(time.RFC3339)) - - cred, err := credentialBuilder.Build() + credentialResponse, err := s.credential.CreateCredential(credentialRequest) if err != nil { - errMsg := "could not build credential" - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not create credential") } - credentialStorageRequest := credentialstorage.StoredCredential{ - ID: cred.ID, - Credential: *cred, - Issuer: gotManifest.Manifest.Issuer.ID, - Subject: request.RequesterDID, - Schema: od.Schema, - IssuanceDate: time.Now().Format(time.RFC3339), - } + creds = append(creds, credentialResponse.Credential) + } - if err := s.credentialStorage.StoreCredential(credentialStorageRequest); err != nil { - errMsg := "could not store credential" - return nil, util.LoggingErrorMsg(err, errMsg) - } + var descriptors []exchange.SubmissionDescriptor + for i, cred := range creds { + // TODO(gabe) build this correctly based on the generated credential format and envelope type + descriptors = append(descriptors, exchange.SubmissionDescriptor{ + ID: cred.ID, + Format: string(exchange.JWTVC), + Path: fmt.Sprintf("$.verifiableCredential[%d]", i), + }) + } - creds = append(creds, *cred) + // set the information for the fulfilled credentials in the response + if err := responseBuilder.SetFulfillment(descriptors); err != nil { + return nil, util.LoggingErrorMsg(err, "could not fulfill credential application: could not set fulfillment") + } + credRes, err := responseBuilder.Build() + if err != nil { + return nil, util.LoggingErrorMsg(err, "could not build response") + } + + // store the response we've generated + storeResponseRequest := manifeststorage.StoredResponse{ + ID: credRes.ID, + Response: *credRes, + ManifestID: request.Application.ManifestID, + } + if err := s.manifestStorage.StoreResponse(storeResponseRequest); err != nil { + return nil, util.LoggingErrorMsg(err, "could not store manifest response") } response := SubmitApplicationResponse{Response: *credRes, Credential: creds} @@ -265,8 +252,7 @@ func (s Service) GetApplications() (*GetApplicationsResponse, error) { gotApps, err := s.manifestStorage.GetApplications() if err != nil { - errMsg := fmt.Sprintf("could not get application(s)") - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not get application(s)") } var apps []manifest.CredentialApplication @@ -310,8 +296,7 @@ func (s Service) GetResponses() (*GetResponsesResponse, error) { gotResponses, err := s.manifestStorage.GetResponses() if err != nil { - errMsg := fmt.Sprintf("could not get response(s)") - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not get response(s)") } var responses []manifest.CredentialResponse diff --git a/pkg/service/manifest/storage/storage.go b/pkg/service/manifest/storage/storage.go index 9a94780df..9554f72eb 100644 --- a/pkg/service/manifest/storage/storage.go +++ b/pkg/service/manifest/storage/storage.go @@ -2,6 +2,7 @@ package storage import ( "fmt" + "github.com/TBD54566975/ssi-sdk/credential/manifest" "github.com/tbd54566975/ssi-service/internal/util" @@ -27,19 +28,26 @@ type StoredResponse struct { } type Storage interface { - // Credential Manifest + CredentialManifestStorage + CredentialApplicationStorage + CredentialResponseStorage +} + +type CredentialManifestStorage interface { StoreManifest(manifest StoredManifest) error GetManifest(id string) (*StoredManifest, error) GetManifests() ([]StoredManifest, error) DeleteManifest(id string) error +} - // Credential Application +type CredentialApplicationStorage interface { StoreApplication(application StoredApplication) error GetApplication(id string) (*StoredApplication, error) GetApplications() ([]StoredApplication, error) DeleteApplication(id string) error +} - // Credential Response +type CredentialResponseStorage interface { StoreResponse(response StoredResponse) error GetResponse(id string) (*StoredResponse, error) GetResponses() ([]StoredResponse, error) diff --git a/pkg/service/schema/schema.go b/pkg/service/schema/schema.go index 40c52c572..a67507751 100644 --- a/pkg/service/schema/schema.go +++ b/pkg/service/schema/schema.go @@ -2,22 +2,28 @@ package schema import ( "fmt" + "time" + "github.com/TBD54566975/ssi-sdk/credential/schema" schemalib "github.com/TBD54566975/ssi-sdk/schema" "github.com/goccy/go-json" "github.com/google/uuid" "github.com/pkg/errors" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/internal/util" "github.com/tbd54566975/ssi-service/pkg/service/framework" + "github.com/tbd54566975/ssi-service/pkg/service/keystore" schemastorage "github.com/tbd54566975/ssi-service/pkg/service/schema/storage" "github.com/tbd54566975/ssi-service/pkg/storage" - "time" ) type Service struct { storage schemastorage.Storage config config.SchemaServiceConfig + + // external dependencies + keyStore *keystore.Service } func (s Service) Type() framework.Type { @@ -38,15 +44,16 @@ func (s Service) Config() config.SchemaServiceConfig { return s.config } -func NewSchemaService(config config.SchemaServiceConfig, s storage.ServiceStorage) (*Service, error) { +func NewSchemaService(config config.SchemaServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service) (*Service, error) { schemaStorage, err := schemastorage.NewSchemaStorage(s) if err != nil { errMsg := "could not instantiate storage for the schema service" return nil, util.LoggingErrorMsg(err, errMsg) } return &Service{ - storage: schemaStorage, - config: config, + storage: schemaStorage, + config: config, + keyStore: keyStore, }, nil } diff --git a/pkg/service/service.go b/pkg/service/service.go index d31a534c6..6122e42d5 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -9,6 +9,7 @@ import ( "github.com/tbd54566975/ssi-service/pkg/service/did" "github.com/tbd54566975/ssi-service/pkg/service/dwn" "github.com/tbd54566975/ssi-service/pkg/service/framework" + "github.com/tbd54566975/ssi-service/pkg/service/keystore" "github.com/tbd54566975/ssi-service/pkg/service/manifest" "github.com/tbd54566975/ssi-service/pkg/service/schema" "github.com/tbd54566975/ssi-service/pkg/storage" @@ -39,12 +40,24 @@ func validateServiceConfig(config config.ServicesConfig) error { if !storage.IsStorageAvailable(config.StorageProvider) { return fmt.Errorf("%s storage provider configured, but not available", config.StorageProvider) } + if config.KeyStoreConfig.IsEmpty() { + return fmt.Errorf("%s no config provided", framework.KeyStore) + } if config.DIDConfig.IsEmpty() { return fmt.Errorf("%s no config provided", framework.DID) } if config.SchemaConfig.IsEmpty() { return fmt.Errorf("%s no config provided", framework.Schema) } + if config.CredentialConfig.IsEmpty() { + return fmt.Errorf("%s no config provided", framework.Credential) + } + if config.ManifestConfig.IsEmpty() { + return fmt.Errorf("%s no config provided", framework.Manifest) + } + if config.DWNConfig.IsEmpty() { + return fmt.Errorf("%s no config provided", framework.DWN) + } return nil } @@ -61,35 +74,35 @@ func instantiateServices(config config.ServicesConfig) ([]framework.Service, err return nil, util.LoggingErrorMsg(err, errMsg) } - didService, err := did.NewDIDService(config.DIDConfig, storageProvider) + keyStoreService, err := keystore.NewKeyStoreService(config.KeyStoreConfig, storageProvider) if err != nil { - errMsg := "could not instantiate the DID service" - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not instantiate keystore service") } - schemaService, err := schema.NewSchemaService(config.SchemaConfig, storageProvider) + didService, err := did.NewDIDService(config.DIDConfig, storageProvider, keyStoreService) if err != nil { - errMsg := "could not instantiate the schema service" - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not instantiate the DID service") } - credentialService, err := credential.NewCredentialService(config.CredentialConfig, storageProvider) + schemaService, err := schema.NewSchemaService(config.SchemaConfig, storageProvider, keyStoreService) if err != nil { - errMsg := "could not instantiate the credential service" - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not instantiate the schema service") } - manifestService, err := manifest.NewManifestService(config.ManifestConfig, storageProvider) + credentialService, err := credential.NewCredentialService(config.CredentialConfig, storageProvider, keyStoreService) if err != nil { - errMsg := "could not instantiate the manifest service" - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not instantiate the credential service") } - dwnService, err := dwn.NewDWNService(config.DWNConfig, storageProvider) + manifestService, err := manifest.NewManifestService(config.ManifestConfig, storageProvider, keyStoreService, credentialService) if err != nil { - errMsg := "could not instantiate the dwn service" - return nil, util.LoggingErrorMsg(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not instantiate the manifest service") + } + + dwnService, err := dwn.NewDWNService(config.DWNConfig, storageProvider, keyStoreService) + if err != nil { + return nil, util.LoggingErrorMsg(err, "could not instantiate the dwn service") } - return []framework.Service{didService, schemaService, credentialService, manifestService, dwnService}, nil + return []framework.Service{keyStoreService, didService, schemaService, credentialService, manifestService, dwnService}, nil }