Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Adding credential application CRUD and validation #94

Merged
merged 10 commits into from
Sep 19, 2022
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ go 1.17

require (
github.com/BurntSushi/toml v1.2.0
github.com/TBD54566975/ssi-sdk v0.0.0-20220719010135-e2fdcfb80e49
github.com/TBD54566975/ssi-sdk v0.0.1-alpha.0.20220915152202-18c69f474901
github.com/ardanlabs/conf v1.5.0
github.com/dimfeld/httptreemux/v5 v5.4.0
github.com/go-playground/locales v0.14.0
Expand All @@ -28,7 +28,7 @@ require github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 // indi

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-playground/validator/v10 v10.11.0 // indirect
Expand All @@ -42,7 +42,7 @@ require (
github.com/multiformats/go-base32 v0.0.3 // indirect
github.com/multiformats/go-base36 v0.1.0 // indirect
github.com/multiformats/go-multibase v0.1.1 // indirect
github.com/multiformats/go-multicodec v0.5.0 // indirect
github.com/multiformats/go-multicodec v0.6.0 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect
github.com/piprate/json-gold v0.4.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand All @@ -53,7 +53,7 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
go.opentelemetry.io/otel v1.9.0
go.opentelemetry.io/otel/sdk v1.9.0
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ 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.0-20220719010135-e2fdcfb80e49 h1:BozkJ4jg1nZyTzBs/ltNq+KtTuveZDh48Ax85cVh0M4=
github.com/TBD54566975/ssi-sdk v0.0.0-20220719010135-e2fdcfb80e49/go.mod h1:uWJkLbobBINP2QFVFL5kku5GtCmbmggzCHh8sTH5NYs=
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/ardanlabs/conf v1.5.0 h1:5TwP6Wu9Xi07eLFEpiCUF3oQXh9UzHMDVnD3u/I5d5c=
github.com/ardanlabs/conf v1.5.0/go.mod h1:ILsMo9dMqYzCxDjDXTiwMI0IgxOJd0MOiucbQY2wlJw=
github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
Expand All @@ -13,6 +15,8 @@ github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/dimfeld/httptreemux/v5 v5.4.0 h1:IiHYEjh+A7pYbhWyjmGnj5HZK6gpOOvyBXCJ+BE8/Gs=
github.com/dimfeld/httptreemux/v5 v5.4.0/go.mod h1:QeEylH57C0v3VO0tkKraVz9oD3Uu93CKPnTLbsidvSw=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
Expand Down Expand Up @@ -73,6 +77,8 @@ github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyD
github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8=
github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs=
github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues=
github.com/multiformats/go-multicodec v0.6.0 h1:KhH2kSuCARyuJraYMFxrNO3DqIaYhOdS039kbhgVwpE=
github.com/multiformats/go-multicodec v0.6.0/go.mod h1:GUC8upxSBE4oG+q3kWZRw/+6yC1BqO550bjhWsJbZlw=
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 h1:Yl0tPBa8QPjGmesFh1D0rDy+q1Twx6FyU7VWHi8wZbI=
Expand Down Expand Up @@ -137,6 +143,8 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
Expand Down
257 changes: 245 additions & 12 deletions pkg/server/router/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package router
import (
"context"
"fmt"
"github.com/TBD54566975/ssi-sdk/credential/exchange"
"github.com/TBD54566975/ssi-sdk/credential"
manifestsdk "github.com/TBD54566975/ssi-sdk/credential/manifest"
"github.com/tbd54566975/ssi-service/pkg/service/manifest"
"net/http"
Expand All @@ -23,29 +23,22 @@ func NewManifestRouter(s svcframework.Service) (*ManifestRouter, error) {
if s == nil {
return nil, errors.New("service cannot be nil")
}
credService, ok := s.(*manifest.Service)
manifestService, ok := s.(*manifest.Service)
if !ok {
return nil, fmt.Errorf("could not create manifest router with service type: %s", s.Type())
}
return &ManifestRouter{
service: credService,
service: manifestService,
}, nil
}

type CreateManifestRequest struct {
Issuer string `json:"issuer" validate:"required"`
// A context is optional. If not present, we'll apply default, required context values.
Context string `json:"@context"`
OutputDescriptors []manifestsdk.OutputDescriptor `json:"outputDescriptors" validate:"required"`
PresentationDefinition exchange.PresentationDefinition `json:"presentationDefinition" validate:"required"`
Manifest manifestsdk.CredentialManifest `json:"manifest" validate:"required"`
}

func (c CreateManifestRequest) ToServiceRequest() manifest.CreateManifestRequest {
return manifest.CreateManifestRequest{
Issuer: c.Issuer,
Context: c.Context,
OutputDescriptors: c.OutputDescriptors,
PresentationDefinition: c.PresentationDefinition,
Manifest: c.Manifest,
}
}

Expand Down Expand Up @@ -182,3 +175,243 @@ func (mr ManifestRouter) DeleteManifest(ctx context.Context, w http.ResponseWrit

return framework.Respond(ctx, w, nil, http.StatusOK)
}

type SubmitApplicationRequest struct {
Application manifestsdk.CredentialApplication `json:"application" validate:"required"`
// Once we have JWT signed wrapper that can get the did this can be removed
RequesterDID string `json:"requesterDid" validate:"required"`
}

func (sar SubmitApplicationRequest) ToServiceRequest() manifest.SubmitApplicationRequest {
return manifest.SubmitApplicationRequest{
Application: sar.Application,
RequesterDID: sar.RequesterDID,
}
}

type SubmitApplicationResponse struct {
nitro-neal marked this conversation as resolved.
Show resolved Hide resolved
Response manifestsdk.CredentialResponse `json:"response"`
Credentials []credential.VerifiableCredential `json:"credentials"`
}

// SubmitApplication godoc
// @Summary Submit application
// @Description Submit application
// @Tags ApplicationAPI
// @Accept json
// @Produce json
// @Param request body SubmitApplicationRequest true "request body"
// @Success 201 {object} SubmitApplicationResponse
// @Failure 400 {string} string "Bad request"
// @Failure 500 {string} string "Internal server error"
// @Router /v1/manifests/applications [put]
func (mr ManifestRouter) SubmitApplication(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
var request SubmitApplicationRequest
if err := framework.Decode(r, &request); err != nil {
errMsg := "invalid submit application request"
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
}

req := request.ToServiceRequest()
submitApplicationResponse, err := mr.service.SubmitApplication(req)
if err != nil {
errMsg := "could not submit application"
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusInternalServerError)
}

resp := SubmitApplicationResponse{Response: submitApplicationResponse.Response, Credentials: submitApplicationResponse.Credential}

return framework.Respond(ctx, w, resp, http.StatusCreated)
}

type GetApplicationResponse struct {
ID string `json:"id"`
Application manifestsdk.CredentialApplication `json:"application"`
}

// GetApplication godoc
// @Summary Get application
// @Description Get application by id
// @Tags ApplicationAPI
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {object} GetApplicationResponse
// @Failure 400 {string} string "Bad request"
// @Router /v1/manifests/applications/{id} [get]
func (mr ManifestRouter) GetApplication(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
id := framework.GetParam(ctx, IDParam)
if id == nil {
errMsg := "cannot get application without ID parameter"
logrus.Error(errMsg)
return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest)
}

gotApplication, err := mr.service.GetApplication(manifest.GetApplicationRequest{ID: *id})
if err != nil {
errMsg := fmt.Sprintf("could not get application with id: %s", *id)
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
}

resp := GetApplicationResponse{
ID: gotApplication.Application.ID,
Application: gotApplication.Application,
}
return framework.Respond(ctx, w, resp, http.StatusOK)
}

type GetApplicationsResponse struct {
Applications []manifestsdk.CredentialApplication `json:"applications"`
}

// GetApplications godoc
// @Summary Get applications
// @Description Checks for the presence of a query parameter and calls the associated filtered get method
// @Tags ApplicationAPI
// @Accept json
// @Produce json
// @Success 200 {object} GetApplicationsResponse
// @Failure 400 {string} string "Bad request"
// @Failure 500 {string} string "Internal server error"
// @Router /v1/manifests/applications [get]
func (mr ManifestRouter) GetApplications(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
gotApplications, err := mr.service.GetApplications()

if err != nil {
errMsg := fmt.Sprintf("could not get applications")
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
}

resp := GetApplicationsResponse{
Applications: gotApplications.Applications,
}

return framework.Respond(ctx, w, resp, http.StatusOK)
}

// DeleteApplication godoc
// @Summary Delete applications
// @Description Delete application by ID
// @Tags ApplicationAPI
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "Bad request"
// @Failure 500 {string} string "Internal server error"
// @Router /v1/manifests/applications/{id} [delete]
func (mr ManifestRouter) DeleteApplication(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
id := framework.GetParam(ctx, IDParam)
if id == nil {
errMsg := "cannot delete application without ID parameter"
logrus.Error(errMsg)
return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest)
}

if err := mr.service.DeleteApplication(manifest.DeleteApplicationRequest{ID: *id}); err != nil {
errMsg := fmt.Sprintf("could not delete application with id: %s", *id)
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusInternalServerError)
}

return framework.Respond(ctx, w, nil, http.StatusOK)
}

type GetResponseResponse struct {
ID string `json:"id"`
Response manifestsdk.CredentialResponse `json:"response"`
}

// GetResponse godoc
// @Summary Get response
// @Description Get response by id
// @Tags ResponseAPI
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {object} GetResponseResponse
// @Failure 400 {string} string "Bad request"
// @Router /v1/manifests/responses/{id} [get]
func (mr ManifestRouter) GetResponse(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
id := framework.GetParam(ctx, IDParam)
if id == nil {
errMsg := "cannot get response without ID parameter"
logrus.Error(errMsg)
return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest)
}

gotResponse, err := mr.service.GetResponse(manifest.GetResponseRequest{ID: *id})
if err != nil {
errMsg := fmt.Sprintf("could not get response with id: %s", *id)
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
}

resp := GetResponseResponse{
ID: gotResponse.Response.ID,
Response: gotResponse.Response,
}
return framework.Respond(ctx, w, resp, http.StatusOK)
}

type GetResponsesResponse struct {
Responses []manifestsdk.CredentialResponse `json:"responses"`
}

// GetResponses godoc
// @Summary Get responses
// @Description Checks for the presence of a query parameter and calls the associated filtered get method
// @Tags ResponseAPI
// @Accept json
// @Produce json
// @Success 200 {object} GetResponsesResponse
// @Failure 400 {string} string "Bad request"
// @Failure 500 {string} string "Internal server error"
// @Router /v1/manifests/responses [get]
func (mr ManifestRouter) GetResponses(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
gotResponses, err := mr.service.GetResponses()

if err != nil {
errMsg := fmt.Sprintf("could not get responses")
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusBadRequest)
}

resp := GetResponsesResponse{
Responses: gotResponses.Responses,
}

return framework.Respond(ctx, w, resp, http.StatusOK)
}

// DeleteResponse godoc
// @Summary Delete responses
// @Description Delete response by ID
// @Tags ResponseAPI
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {string} string "OK"
// @Failure 400 {string} string "Bad request"
// @Failure 500 {string} string "Internal server error"
// @Router /v1/manifests/responses/{id} [delete]
func (mr ManifestRouter) DeleteResponse(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
id := framework.GetParam(ctx, IDParam)
if id == nil {
errMsg := "cannot delete response without ID parameter"
logrus.Error(errMsg)
return framework.NewRequestErrorMsg(errMsg, http.StatusBadRequest)
}

if err := mr.service.DeleteResponse(manifest.DeleteResponseRequest{ID: *id}); err != nil {
errMsg := fmt.Sprintf("could not delete response with id: %s", *id)
logrus.WithError(err).Error(errMsg)
return framework.NewRequestError(errors.Wrap(err, errMsg), http.StatusInternalServerError)
}

return framework.Respond(ctx, w, nil, http.StatusOK)
}
Loading