diff --git a/ci/azure-pipelines.yml b/ci/azure-pipelines.yml index c9b702b62..72841602a 100644 --- a/ci/azure-pipelines.yml +++ b/ci/azure-pipelines.yml @@ -54,4 +54,4 @@ jobs: docker push docker.pkg.github.com/trustbloc/edge-service/vc-rest:$VC_REST_TAG env: DOCKER_USER: $(DOCKER_USER) - DOCKER_PASSWORD: $(DOCKER_PASSWORD) \ No newline at end of file + DOCKER_PASSWORD: $(DOCKER_PASSWORD) diff --git a/cmd/vc-rest/go.mod b/cmd/vc-rest/go.mod index bb3d4ebb6..dea696473 100644 --- a/cmd/vc-rest/go.mod +++ b/cmd/vc-rest/go.mod @@ -11,6 +11,7 @@ require ( github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.5 github.com/stretchr/testify v1.4.0 + github.com/trustbloc/edge-core v0.0.0-20200117135316-f80bd93997ef github.com/trustbloc/edge-service v0.0.0 ) diff --git a/cmd/vc-rest/go.sum b/cmd/vc-rest/go.sum index 73dd19acc..4c14726ce 100644 --- a/cmd/vc-rest/go.sum +++ b/cmd/vc-rest/go.sum @@ -5,6 +5,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/VictoriaMetrics/fastcache v1.5.5 h1:HsBlzPgzKG0566YOl1mmfyz8SCU0zLKfbl9RDLsiLD8= github.com/VictoriaMetrics/fastcache v1.5.5/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.25.39/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= @@ -20,8 +21,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-language-server/uri v0.2.0 h1:zkFlKR0EYmCg3076hwVbM9/+/Ugr8vMQvQQgoS2JpTo= -github.com/go-language-server/uri v0.2.0/go.mod h1:1wEq7lT5PmX5uljJuQJeRxdW06jr5VfA1aR1FKe2/gc= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= @@ -39,10 +38,10 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.2-0.20190829225427-b1c9c4891a65/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/tink v1.3.0-rc3/go.mod h1:xCAsc4J1ZYTyVncY9QgOTZsU0l+P3ou0VsiLslNjgAo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= @@ -53,16 +52,18 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hyperledger/aries-framework-go v0.1.0 h1:ndBiM5JKBsQ1lrOnnB5resLr1gxdlOg0EAP0w3wiNas= -github.com/hyperledger/aries-framework-go v0.1.0/go.mod h1:YY/ZoD5NpSjGwGlxOQDt7yI7N8mI9BT/zCdYjHPxGjw= github.com/hyperledger/aries-framework-go v0.1.1-0.20200113160002-41ea60bef355 h1:NUrliVMvnPd35H8T9xVDZCMXMy0vpBNInUL2Dy2pnho= github.com/hyperledger/aries-framework-go v0.1.1-0.20200113160002-41ea60bef355/go.mod h1:1wIgYlQulTD2fQSrslEalfuQADm1VB0UBDTPZJvQeFg= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= @@ -78,7 +79,6 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/piprate/json-gold v0.2.0/go.mod h1:5EEeMX0Gg1CyQxoy4QRhufCfMSCOvcRAaqwkrn6NqqY= github.com/piprate/json-gold v0.3.0 h1:a1vHx7Q1jOO1pjCtKwTI/WCzwaQwRt9VM7apK2uy200= github.com/piprate/json-gold v0.3.0/go.mod h1:OK1z7UgtBZk06n2cDE2OSq1kffmjFFp5/2yhLLCz9UM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -106,6 +106,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/trustbloc/edge-core v0.0.0-20200117135316-f80bd93997ef h1:DxV490TVnFaHeHpNKeRfS2X7MLWJVc8D+94FAGkbl8M= +github.com/trustbloc/edge-core v0.0.0-20200117135316-f80bd93997ef/go.mod h1:aEkFOyP99eRGPLwCN/4XKFe4ZAPmtroMkf49SRirXkU= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -121,9 +123,6 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba h1:9bFeDpN3gTqNanMVqNcoR/pJQuP5uroC3t1D7eXozTE= golang.org/x/crypto v0.0.0-20191119213627-4f8c1d86b1ba/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -132,7 +131,6 @@ golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvx golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -142,7 +140,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -172,10 +169,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191223235410-3721262b3e7c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -188,6 +181,7 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/cmd/vc-rest/startcmd/start.go b/cmd/vc-rest/startcmd/start.go index 317d75098..09483e88a 100644 --- a/cmd/vc-rest/startcmd/start.go +++ b/cmd/vc-rest/startcmd/start.go @@ -13,6 +13,7 @@ import ( "github.com/gorilla/mux" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/trustbloc/edge-core/pkg/storage/memstore" "github.com/trustbloc/edge-service/pkg/restapi/vc/operation" cmdutils "github.com/trustbloc/edge-service/pkg/utils/cmd" @@ -81,7 +82,10 @@ func startEdgeService(parameters *vcRestParameters) error { return errMissingHostURL } - vcService := operation.New() + vcService, err := operation.New(memstore.NewProvider()) + if err != nil { + return err + } handlers := vcService.GetRESTHandlers() router := mux.NewRouter() @@ -91,7 +95,6 @@ func startEdgeService(parameters *vcRestParameters) error { } log.Infof("Starting vc rest server on host %s", parameters.hostURL) - err := parameters.srv.ListenAndServe(parameters.hostURL, router) - return err + return parameters.srv.ListenAndServe(parameters.hostURL, router) } diff --git a/go.mod b/go.mod index 20212494c..6c0179bda 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,11 @@ module github.com/trustbloc/edge-service go 1.13 require ( + github.com/google/uuid v1.1.1 + github.com/gorilla/mux v1.7.3 github.com/hyperledger/aries-framework-go v0.1.1-0.20200113160002-41ea60bef355 github.com/sirupsen/logrus v1.4.2 github.com/spf13/cobra v0.0.5 github.com/stretchr/testify v1.4.0 + github.com/trustbloc/edge-core v0.0.0-20200117135316-f80bd93997ef ) diff --git a/go.sum b/go.sum index 8379b07ad..4c14726ce 100644 --- a/go.sum +++ b/go.sum @@ -41,9 +41,11 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/tink v1.3.0-rc3/go.mod h1:xCAsc4J1ZYTyVncY9QgOTZsU0l+P3ou0VsiLslNjgAo= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -104,6 +106,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/trustbloc/edge-core v0.0.0-20200117135316-f80bd93997ef h1:DxV490TVnFaHeHpNKeRfS2X7MLWJVc8D+94FAGkbl8M= +github.com/trustbloc/edge-core v0.0.0-20200117135316-f80bd93997ef/go.mod h1:aEkFOyP99eRGPLwCN/4XKFe4ZAPmtroMkf49SRirXkU= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= diff --git a/pkg/restapi/vc/controller.go b/pkg/restapi/vc/controller.go index 045348a93..7226824fe 100644 --- a/pkg/restapi/vc/controller.go +++ b/pkg/restapi/vc/controller.go @@ -7,15 +7,21 @@ SPDX-License-Identifier: Apache-2.0 package vc import ( + "github.com/trustbloc/edge-core/pkg/storage" + "github.com/trustbloc/edge-service/pkg/restapi/vc/operation" ) // New returns new controller instance. -func New() (*Controller, error) { +func New(provider storage.Provider) (*Controller, error) { var allHandlers []operation.Handler - issueService := operation.New() - allHandlers = append(allHandlers, issueService.GetRESTHandlers()...) + vcService, err := operation.New(provider) + if err != nil { + return nil, err + } + + allHandlers = append(allHandlers, vcService.GetRESTHandlers()...) return &Controller{handlers: allHandlers}, nil } diff --git a/pkg/restapi/vc/controller_test.go b/pkg/restapi/vc/controller_test.go index 7f1eaa525..a9be52454 100644 --- a/pkg/restapi/vc/controller_test.go +++ b/pkg/restapi/vc/controller_test.go @@ -11,22 +11,24 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/trustbloc/edge-core/pkg/storage/memstore" ) func TestController_New(t *testing.T) { - controller, err := New() + controller, err := New(memstore.NewProvider()) require.NoError(t, err) require.NotNil(t, controller) } func TestController_GetOperations(t *testing.T) { - controller, err := New() + controller, err := New(memstore.NewProvider()) require.NoError(t, err) require.NotNil(t, controller) ops := controller.GetOperations() - require.Equal(t, 1, len(ops)) + require.Equal(t, 3, len(ops)) require.Equal(t, "/credential", ops[0].Path()) require.Equal(t, http.MethodPost, ops[0].Method()) diff --git a/pkg/restapi/vc/operation/models.go b/pkg/restapi/vc/operation/models.go index 10a0cb1c2..3c10c1194 100644 --- a/pkg/restapi/vc/operation/models.go +++ b/pkg/restapi/vc/operation/models.go @@ -6,7 +6,11 @@ SPDX-License-Identifier: Apache-2.0 package operation -import "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" +import ( + "time" + + "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" +) // CreateCrendential input data for edge service issuer rest api type CreateCrendential struct { @@ -14,3 +18,17 @@ type CreateCrendential struct { Issuer verifiable.Issuer `json:"issuer"` Type []string `json:"type,omitempty"` } + +// ProfileRequest struct the input for creating profile +type ProfileRequest struct { + DID string `json:"did"` + URI string `json:"uri"` +} + +// ProfileResponse struct the output for creating profile +type ProfileResponse struct { + ID string `json:"id"` + URI string `json:"uri"` + IssueDate *time.Time `json:"issueDate"` + DID string `json:"did"` +} diff --git a/pkg/restapi/vc/operation/operations.go b/pkg/restapi/vc/operation/operations.go index c505e32c4..09c71550a 100644 --- a/pkg/restapi/vc/operation/operations.go +++ b/pkg/restapi/vc/operation/operations.go @@ -8,24 +8,39 @@ package operation import ( "encoding/json" + "errors" "fmt" + "io" "net/http" + "net/url" + "path" "time" + "github.com/google/uuid" + "github.com/gorilla/mux" + "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" log "github.com/sirupsen/logrus" + "github.com/trustbloc/edge-core/pkg/storage" "github.com/trustbloc/edge-service/pkg/internal/common/support" ) const ( + credential = "credential" createCredentialEndpoint = "/credential" + createProfileEndpoint = "/profile" credentialContext = "https://www.w3.org/2018/credentials/v1" + profilePathVariable = "profileID" + + getProfileEndpoint = "/profile/{" + profilePathVariable // ID is the identifier for the verifiable credential ID = "https://example.com/credentials/1872" // TODO create the profile and get the prefix of the ID from the profile issue-47 ) +var errProfileNotFound = errors.New("specified profile ID does not exist") + // Handler http handler for each controller API endpoint type Handler interface { Path() string @@ -33,17 +48,26 @@ type Handler interface { Handle() http.HandlerFunc } -// New returns CreateCrendential instance -func New() *Operation { - svc := &Operation{} +// New returns CreateCredential instance +func New(provider storage.Provider) (*Operation, error) { + store, err := provider.OpenStore(credential) + if err != nil { + return nil, err + } + + profileStore := NewProfile(store) + svc := &Operation{ + profileStore: profileStore, + } svc.registerHandler() - return svc + return svc, nil } -// Operation defines handlers for VC service +// Operation defines handlers for Edge service type Operation struct { - handlers []Handler + handlers []Handler + profileStore *Profile } func (c *Operation) createCredentialHandler(rw http.ResponseWriter, req *http.Request) { @@ -51,12 +75,7 @@ func (c *Operation) createCredentialHandler(rw http.ResponseWriter, req *http.Re err := json.NewDecoder(req.Body).Decode(&data) if err != nil { - rw.WriteHeader(http.StatusBadRequest) - _, err = rw.Write([]byte(fmt.Sprintf("Receieved invalid request: %s", err.Error()))) - - if err != nil { - log.Errorf("Failed to write response for credential creation failure (unable to read request): %s", err.Error()) - } + c.writeErrorResponse(rw, http.StatusBadRequest, "Failed to write response for invalid request received") return } @@ -64,38 +83,66 @@ func (c *Operation) createCredentialHandler(rw http.ResponseWriter, req *http.Re validCredential, err := createCredential(&data) if err != nil { - rw.WriteHeader(http.StatusBadRequest) - _, err = rw.Write([]byte(fmt.Sprintf("validation failed for vc: %s", err.Error()))) - - if err != nil { - log.Errorf("Failed to write response for create credential failure: %s", err.Error()) - } + c.writeErrorResponse(rw, http.StatusBadRequest, "Failed to write response for create credential failure") return } + rw.WriteHeader(http.StatusCreated) c.writeResponse(rw, validCredential) } -// writeResponse writes interface value to response -func (c *Operation) writeResponse(rw http.ResponseWriter, v interface{}) { +func (c *Operation) createProfileHandler(rw http.ResponseWriter, req *http.Request) { + data := ProfileRequest{} + err := json.NewDecoder(req.Body).Decode(&data) + + if err != nil { + c.writeErrorResponse(rw, http.StatusBadRequest, "Failed to write response for invalid request received") + + return + } + + profileResponse, err := c.createProfile(&data) + + if err != nil { + c.writeErrorResponse(rw, http.StatusBadRequest, err.Error()) + + return + } + rw.WriteHeader(http.StatusCreated) - err := json.NewEncoder(rw).Encode(v) - // as of now, just log errors for writing response + c.writeResponse(rw, profileResponse) +} + +func (c *Operation) getProfileHandler(rw http.ResponseWriter, req *http.Request) { + vars := mux.Vars(req) + profileID := vars[profilePathVariable] + + profileResponseJSON, err := c.profileStore.GetProfile(profileID) if err != nil { - log.Errorf("Unable to send error response, %s", err) + if err == errProfileNotFound { + c.writeErrorResponse(rw, http.StatusNotFound, "Failed to find the profile") + + return + } + + c.writeErrorResponse(rw, http.StatusBadRequest, err.Error()) + + return } + + c.writeResponse(rw, profileResponseJSON) } func createCredential(data *CreateCrendential) (*verifiable.Credential, error) { credential := &verifiable.Credential{} - issueDate := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), - time.Now().Hour(), time.Now().Minute(), time.Now().Second(), 0, time.UTC) + issueDate := time.Now().UTC() credential.Context = []string{credentialContext} credential.Subject = data.Subject credential.Types = data.Type credential.Issuer = data.Issuer credential.Issued = &issueDate + // TODO to be replaced by getting profile ID issue-47 credential.ID = ID cred, err := json.Marshal(credential) @@ -111,11 +158,69 @@ func createCredential(data *CreateCrendential) (*verifiable.Credential, error) { return validatedCred, nil } +func (c *Operation) createProfile(pr *ProfileRequest) (*ProfileResponse, error) { + if pr.DID == "" { + return nil, fmt.Errorf("missing DID information") + } + + if pr.URI == "" { + return nil, fmt.Errorf("missing URI information") + } + + u, err := parseAndGetURI(pr.URI) + if err != nil { + return nil, err + } + + issueDate := time.Now().UTC() + profileResponse := &ProfileResponse{ + ID: uuid.New().String(), + URI: u, + IssueDate: &issueDate, + DID: pr.DID, + } + + err = c.profileStore.SaveProfile(profileResponse) + if err != nil { + return nil, err + } + + return profileResponse, nil +} +func parseAndGetURI(uri string) (string, error) { + u, err := url.Parse(uri) + if err != nil { + return "", fmt.Errorf("failed to parse the uri: %s", err.Error()) + } + + u.Path = path.Join(u.Path, uuid.New().String()) + + return u.String(), nil +} + +// writeResponse writes interface value to response +func (c *Operation) writeResponse(rw io.Writer, v interface{}) { + err := json.NewEncoder(rw).Encode(v) + if err != nil { + log.Errorf("Unable to send error response, %s", err) + } +} + +func (c *Operation) writeErrorResponse(rw http.ResponseWriter, status int, msg string) { + rw.WriteHeader(status) + + if _, err := rw.Write([]byte(msg)); err != nil { + log.Errorf("Unable to send error message, %s", err) + } +} + // registerHandler register handlers to be exposed from this service as REST API endpoints func (c *Operation) registerHandler() { // Add more protocol endpoints here to expose them as controller API endpoints c.handlers = []Handler{ support.NewHTTPHandler(createCredentialEndpoint, http.MethodPost, c.createCredentialHandler), + support.NewHTTPHandler(createProfileEndpoint, http.MethodPost, c.createProfileHandler), + support.NewHTTPHandler(getProfileEndpoint, http.MethodGet, c.getProfileHandler), } } diff --git a/pkg/restapi/vc/operation/operations_test.go b/pkg/restapi/vc/operation/operations_test.go index 53e7fbf30..e01bc23a2 100644 --- a/pkg/restapi/vc/operation/operations_test.go +++ b/pkg/restapi/vc/operation/operations_test.go @@ -14,11 +14,12 @@ import ( "net/http/httptest" "testing" + "github.com/gorilla/mux" "github.com/hyperledger/aries-framework-go/pkg/doc/verifiable" - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" + "github.com/trustbloc/edge-core/pkg/storage" + "github.com/trustbloc/edge-core/pkg/storage/memstore" ) const ( @@ -62,9 +63,22 @@ const ( } }` ) +const ( + testIssuerProfile = `{ + "did": "did:peer:22", + "uri": "https://example.com/credentials" +}` +) +const ( + testIncorrectIssuerProfile = `{ + "did": "did:peer:22", + "uri": "&&%^)$" +}` +) func TestCreateCredentialHandler(t *testing.T) { - op := New() + op, err := New(memstore.NewProvider()) + require.NoError(t, err) createCredentialHandler := getHandler(t, op, createCredentialEndpoint) @@ -90,51 +104,226 @@ func TestCreateCredentialHandler(t *testing.T) { require.Equal(t, ID, vc.ID) }) t.Run("create credential error by passing invalid request", func(t *testing.T) { - req, err := http.NewRequest(http.MethodPost, "/credentials", bytes.NewBuffer([]byte(""))) + req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, bytes.NewBuffer([]byte(""))) require.NoError(t, err) rr := httptest.NewRecorder() createCredentialHandler.Handle().ServeHTTP(rr, req) require.Equal(t, http.StatusBadRequest, rr.Code) - require.Equal(t, rr.Body.String(), "Receieved invalid request: EOF") + require.Equal(t, rr.Body.String(), "Failed to write response for invalid request received") }) t.Run("create credential error by passing invalid credential object", func(t *testing.T) { - req, err := http.NewRequest(http.MethodPost, "/credentials", bytes.NewBuffer([]byte(testIncorrectCredential))) + req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, + bytes.NewBuffer([]byte(testIncorrectCredential))) require.NoError(t, err) rr := httptest.NewRecorder() createCredentialHandler.Handle().ServeHTTP(rr, req) require.Equal(t, http.StatusBadRequest, rr.Code) require.Equal(t, rr.Body.String(), - "validation failed for vc: failed to create new credential: build new credential: "+ - "fill credential types from raw: credential type of unknown structure") + "Failed to write response for create credential failure") }) t.Run("create credential error unable to write a response while reading the request", func(t *testing.T) { - req, err := http.NewRequest(http.MethodPost, "/credentials", bytes.NewBuffer([]byte(""))) + req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, bytes.NewBuffer([]byte(""))) require.NoError(t, err) rw := mockResponseWriter{} createCredentialHandler.Handle().ServeHTTP(rw, req) require.Contains(t, logContents.String(), - "Failed to write response for credential creation failure (unable to read request)") + "Unable to send error message, response writer failed") }) - t.Run("create credential error while writing the create credential failure", func(t *testing.T) { - req, err := http.NewRequest(http.MethodPost, "/credentials", bytes.NewBuffer([]byte(testIncorrectCredential))) +} + +func TestCreateProfileHandler(t *testing.T) { + op, err := New(memstore.NewProvider()) + require.NoError(t, err) + + createProfileHandler := getHandler(t, op, createProfileEndpoint) + + var logContents bytes.Buffer + + log.SetOutput(&logContents) + + t.Run("create profile success", func(t *testing.T) { + req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, + bytes.NewBuffer([]byte(testIssuerProfile))) + require.NoError(t, err) + rr := httptest.NewRecorder() + + createProfileHandler.Handle().ServeHTTP(rr, req) + profile := ProfileResponse{} + + err = json.Unmarshal(rr.Body.Bytes(), &profile) + require.NoError(t, err) + + require.Equal(t, http.StatusCreated, rr.Code) + require.NotEmpty(t, profile.ID) + require.Contains(t, profile.URI, "https://example.com/credentials") + }) + t.Run("missing DID information", func(t *testing.T) { + prBytes, err := json.Marshal(ProfileRequest{}) + require.NoError(t, err) + + req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer(prBytes)) + require.NoError(t, err) + rr := httptest.NewRecorder() + + createProfileHandler.Handle().ServeHTTP(rr, req) + require.Equal(t, http.StatusBadRequest, rr.Code) + require.Equal(t, rr.Body.String(), "missing DID information") + }) + t.Run("missing URI information", func(t *testing.T) { + prBytes, err := json.Marshal(ProfileRequest{DID: "test"}) + require.NoError(t, err) + + req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer(prBytes)) + require.NoError(t, err) + rr := httptest.NewRecorder() + + createProfileHandler.Handle().ServeHTTP(rr, req) + require.Equal(t, http.StatusBadRequest, rr.Code) + require.Equal(t, rr.Body.String(), "missing URI information") + }) + t.Run("create profile error by passing invalid request", func(t *testing.T) { + req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer([]byte(""))) + require.NoError(t, err) + rr := httptest.NewRecorder() + + createProfileHandler.Handle().ServeHTTP(rr, req) + require.Equal(t, http.StatusBadRequest, rr.Code) + require.Equal(t, rr.Body.String(), "Failed to write response for invalid request received") + }) + t.Run("create profile error by internal create profile failure", func(t *testing.T) { + req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, + bytes.NewBuffer([]byte(testIncorrectIssuerProfile))) + require.NoError(t, err) + rr := httptest.NewRecorder() + + createProfileHandler.Handle().ServeHTTP(rr, req) + require.Equal(t, http.StatusBadRequest, rr.Code) + require.Contains(t, rr.Body.String(), "failed to parse the uri: parse &&%^)$: invalid URL escape") + }) + + t.Run("create profile error unable to write a response while reading the request", func(t *testing.T) { + req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer([]byte(""))) require.NoError(t, err) rw := mockResponseWriter{} - createCredentialHandler.Handle().ServeHTTP(rw, req) + createProfileHandler.Handle().ServeHTTP(rw, req) require.Contains(t, logContents.String(), - "Failed to write response for create credential failure") + "Unable to send error message, response writer failed") + }) + t.Run("create profile error while saving the profile", func(t *testing.T) { + op, err := New(memstore.NewProvider()) + require.NoError(t, err) + op.profileStore = NewProfile(&mockStore{ + get: func(s string) (bytes []byte, e error) { + return nil, storage.ErrValueNotFound + }, + put: func(s string, bytes []byte) error { + return errors.New("db error while saving profile") + }}) + + createProfileHandler = getHandler(t, op, createProfileEndpoint) + req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer([]byte(testIssuerProfile))) + require.NoError(t, err) + rr := httptest.NewRecorder() + createProfileHandler.Handle().ServeHTTP(rr, req) + require.Equal(t, http.StatusBadRequest, rr.Code) + require.Contains(t, rr.Body.String(), "db error while saving profile") }) } -func TestOperation_WriteResponse(t *testing.T) { - svc := New() - require.NotNil(t, svc) - svc.writeResponse(&httptest.ResponseRecorder{}, "token") +func TestGetProfileHandler(t *testing.T) { + op, err := New(memstore.NewProvider()) + require.NoError(t, err) + + getProfileHandler := getHandler(t, op, getProfileEndpoint) + + var logContents bytes.Buffer + + log.SetOutput(&logContents) + + notFoundID := "test" + req, err := http.NewRequest(http.MethodGet, + "/profile/"+notFoundID, + bytes.NewBuffer([]byte(""))) + require.NoError(t, err) + + urlVars := make(map[string]string) + urlVars[profilePathVariable] = notFoundID + + req = mux.SetURLVars(req, urlVars) + + t.Run("get profile success", func(t *testing.T) { + profile := createProfileSuccess(t, op) + + r, err := http.NewRequest(http.MethodGet, + "/profile/"+profile.ID, + bytes.NewBuffer([]byte(""))) + require.NoError(t, err) + + rr := httptest.NewRecorder() + + urlVars := make(map[string]string) + urlVars[profilePathVariable] = profile.ID + req = mux.SetURLVars(r, urlVars) + + getProfileHandler.Handle().ServeHTTP(rr, req) + + require.Equal(t, http.StatusOK, rr.Code) + profileResponse := &ProfileResponse{} + err = json.Unmarshal(rr.Body.Bytes(), profileResponse) + require.NoError(t, err) + require.Equal(t, profileResponse.ID, profile.ID) + require.Equal(t, profileResponse.URI, profile.URI) + }) + t.Run("get profile error, bad request", func(t *testing.T) { + req, err := http.NewRequest(http.MethodGet, + "/profile/"+notFoundID, + bytes.NewBuffer([]byte(""))) + require.NoError(t, err) + rr := httptest.NewRecorder() + getProfileHandler.Handle().ServeHTTP(rr, req) + require.Equal(t, http.StatusBadRequest, rr.Code) + }) +} + +func createProfileSuccess(t *testing.T, op *Operation) *ProfileResponse { + req, err := http.NewRequest(http.MethodPost, createProfileEndpoint, bytes.NewBuffer([]byte(testIssuerProfile))) + require.NoError(t, err) + + rr := httptest.NewRecorder() + + createProfileEndpoint := getHandler(t, op, createProfileEndpoint) + createProfileEndpoint.Handle().ServeHTTP(rr, req) + + profile := &ProfileResponse{} + + err = json.Unmarshal(rr.Body.Bytes(), &profile) + require.NoError(t, err) + + require.Equal(t, http.StatusCreated, rr.Code) + require.NotEmpty(t, profile.ID) + + return profile +} + +func TestOperation_parseAndGetURL(t *testing.T) { + t.Run("parse uri success", func(t *testing.T) { + resp, err := parseAndGetURI("http://example.edu/credentials") + require.NotNil(t, resp) + require.NoError(t, err) + }) + t.Run("parse uri failed", func(t *testing.T) { + resp, err := parseAndGetURI("//not-valid.&&%^)$") + require.Empty(t, resp) + require.Error(t, err) + require.Contains(t, err.Error(), "failed to parse the uri") + }) } func TestCreate(t *testing.T) { b := mockResponseWriter{} - op := New() + op, err := New(memstore.NewProvider()) + require.NoError(t, err) req, err := http.NewRequest(http.MethodPost, createCredentialEndpoint, bytes.NewBuffer([]byte(testCreateCredentialRequest))) require.NoError(t, err) @@ -183,3 +372,18 @@ func (b mockResponseWriter) Write([]byte) (int, error) { func (b mockResponseWriter) WriteHeader(statusCode int) { } + +type mockStore struct { + put func(string, []byte) error + get func(string) ([]byte, error) +} + +// Put stores the key and the record +func (m *mockStore) Put(k string, v []byte) error { + return m.put(k, v) +} + +// Get fetches the record based on key +func (m *mockStore) Get(k string) ([]byte, error) { + return m.get(k) +} diff --git a/pkg/restapi/vc/operation/profile.go b/pkg/restapi/vc/operation/profile.go new file mode 100644 index 000000000..058b20852 --- /dev/null +++ b/pkg/restapi/vc/operation/profile.go @@ -0,0 +1,60 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package operation + +import ( + "encoding/json" + "fmt" + + "github.com/trustbloc/edge-core/pkg/storage" +) + +const ( + keyPattern = "%s_%s" + profileKeyPrefix = "profile" +) + +// NewProfile returns new credential recorder instance +func NewProfile(store storage.Store) *Profile { + return &Profile{store: store} +} + +// Profile takes care of features to be persisted for credentials +type Profile struct { + store storage.Store +} + +// SaveProfile saves issuer profile to underlying store +func (c *Profile) SaveProfile(profileResponse *ProfileResponse) error { + k := fmt.Sprintf(keyPattern, profileKeyPrefix, profileResponse.ID) + bytes, err := json.Marshal(profileResponse) + + if err != nil { + return fmt.Errorf("save profile marshalling error: %s", err.Error()) + } + + return c.store.Put(k, bytes) +} + +// GetProfile returns profile id for given key from underlying store and +// stores the result in the value pointed to by v +func (c *Profile) GetProfile(id string) (*ProfileResponse, error) { + k := fmt.Sprintf(keyPattern, profileKeyPrefix, id) + + bytes, err := c.store.Get(k) + if err != nil { + return nil, err + } + + response := &ProfileResponse{} + + err = json.Unmarshal(bytes, response) + if err != nil { + return nil, err + } + + return response, nil +} diff --git a/pkg/restapi/vc/operation/profile_test.go b/pkg/restapi/vc/operation/profile_test.go new file mode 100644 index 000000000..aee29f92c --- /dev/null +++ b/pkg/restapi/vc/operation/profile_test.go @@ -0,0 +1,76 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 +*/ + +package operation + +import ( + "fmt" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/require" + + mockstorage "github.com/trustbloc/edge-core/pkg/storage/mockstore" +) + +func TestCredentialRecord_SaveProfile(t *testing.T) { + t.Run("test save profile success", func(t *testing.T) { + store := &mockstorage.MockStore{Store: make(map[string][]byte)} + record := NewProfile(store) + require.NotNil(t, record) + + issueDate := time.Now().UTC() + value := &ProfileResponse{ + ID: uuid.New().String(), + URI: "https://example.com/credentials/1872", + IssueDate: &issueDate, + } + + err := record.SaveProfile(value) + require.NoError(t, err) + + require.NotEmpty(t, store) + k := fmt.Sprintf(keyPattern, profileKeyPrefix, value.ID) + v, err := record.store.Get(k) + require.NoError(t, err) + require.NotEmpty(t, v) + }) +} + +func TestCredentialRecord_GetProfile(t *testing.T) { + t.Run("test get profile success", func(t *testing.T) { + store := &mockstorage.MockStore{Store: make(map[string][]byte)} + record := NewProfile(store) + require.NotNil(t, record) + + issueDate := time.Now().UTC() + valueStored := &ProfileResponse{ + ID: uuid.New().String(), + URI: "https://example.com/credentials/1872", + IssueDate: &issueDate, + } + + err := record.SaveProfile(valueStored) + require.NoError(t, err) + + require.NotEmpty(t, store) + + valueFound, err := record.GetProfile(valueStored.ID) + require.NoError(t, err) + require.Equal(t, valueStored, valueFound) + }) + + t.Run("test get profile failure due to invalid id", func(t *testing.T) { + store := &mockstorage.MockStore{Store: make(map[string][]byte)} + record := NewProfile(store) + require.NotNil(t, record) + + profileByte, err := record.GetProfile("") + require.Nil(t, profileByte) + require.Error(t, err) + require.Contains(t, err.Error(), "store does not have a value associated with this key") + }) +}