diff --git a/doc/swagger.yaml b/doc/swagger.yaml index 98284863f..8ee6a7b18 100644 --- a/doc/swagger.yaml +++ b/doc/swagger.yaml @@ -223,16 +223,6 @@ definitions: - id - type type: object - dwn.PublishManifestResponse: - properties: - response: - type: string - status: - type: integer - required: - - response - - status - type: object exchange.ClaimFormat: properties: jwt: @@ -297,6 +287,10 @@ definitions: $ref: '#/definitions/exchange.Filter' id: type: string + intent_to_retain: + type: boolean + name: + type: string optional: type: boolean path: @@ -525,12 +519,16 @@ definitions: type: object github.com_tbd54566975_ssi-service_pkg_server_router.CreateManifestRequest: properties: + description: + type: string format: $ref: '#/definitions/exchange.ClaimFormat' issuerDid: type: string issuerName: type: string + name: + type: string outputDescriptors: items: $ref: '#/definitions/manifest.OutputDescriptor' @@ -551,10 +549,22 @@ definitions: type: object github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionRequest: properties: - presentation_definition: - $ref: '#/definitions/exchange.PresentationDefinition' + format: + $ref: '#/definitions/exchange.ClaimFormat' + inputDescriptors: + items: + $ref: '#/definitions/exchange.InputDescriptor' + type: array + name: + type: string + purpose: + type: string + submissionRequirements: + items: + $ref: '#/definitions/exchange.SubmissionRequirement' + type: array required: - - presentation_definition + - inputDescriptors type: object github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionResponse: properties: @@ -668,10 +678,22 @@ definitions: $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetManifestResponse' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse: + github.com_tbd54566975_ssi-service_pkg_server_router.GetOperationsRequest: properties: - id: + filter: + type: string + parent: type: string + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetOperationsResponse: + properties: + operations: + items: + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.Operation' + type: array + type: object + github.com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse: + properties: presentation_definition: $ref: '#/definitions/exchange.PresentationDefinition' type: object @@ -703,22 +725,7 @@ definitions: $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetSchemaResponse' type: array type: object - github.com_tbd54566975_ssi-service_pkg_server_router.PublishManifestRequest: - properties: - manifestId: - type: string - required: - - manifestId - type: object - github.com_tbd54566975_ssi-service_pkg_server_router.PublishManifestResponse: - properties: - dwnResponse: - $ref: '#/definitions/dwn.PublishManifestResponse' - manifest: - $ref: '#/definitions/manifest.CredentialManifest' - required: - - dwnResponse - - manifest + github.com_tbd54566975_ssi-service_pkg_server_router.Operation: type: object github.com_tbd54566975_ssi-service_pkg_server_router.ResolveDIDResponse: properties: @@ -813,12 +820,16 @@ definitions: type: object manifest.CredentialManifest: properties: + description: + type: string format: $ref: '#/definitions/exchange.ClaimFormat' id: type: string issuer: $ref: '#/definitions/manifest.Issuer' + name: + type: string output_descriptors: items: $ref: '#/definitions/manifest.OutputDescriptor' @@ -952,12 +963,16 @@ definitions: type: object pkg_server_router.CreateManifestRequest: properties: + description: + type: string format: $ref: '#/definitions/exchange.ClaimFormat' issuerDid: type: string issuerName: type: string + name: + type: string outputDescriptors: items: $ref: '#/definitions/manifest.OutputDescriptor' @@ -978,10 +993,22 @@ definitions: type: object pkg_server_router.CreatePresentationDefinitionRequest: properties: - presentation_definition: - $ref: '#/definitions/exchange.PresentationDefinition' + format: + $ref: '#/definitions/exchange.ClaimFormat' + inputDescriptors: + items: + $ref: '#/definitions/exchange.InputDescriptor' + type: array + name: + type: string + purpose: + type: string + submissionRequirements: + items: + $ref: '#/definitions/exchange.SubmissionRequirement' + type: array required: - - presentation_definition + - inputDescriptors type: object pkg_server_router.CreatePresentationDefinitionResponse: properties: @@ -1095,10 +1122,22 @@ definitions: $ref: '#/definitions/pkg_server_router.GetManifestResponse' type: array type: object - pkg_server_router.GetPresentationDefinitionResponse: + pkg_server_router.GetOperationsRequest: properties: - id: + filter: + type: string + parent: type: string + type: object + pkg_server_router.GetOperationsResponse: + properties: + operations: + items: + $ref: '#/definitions/pkg_server_router.Operation' + type: array + type: object + pkg_server_router.GetPresentationDefinitionResponse: + properties: presentation_definition: $ref: '#/definitions/exchange.PresentationDefinition' type: object @@ -1130,22 +1169,7 @@ definitions: $ref: '#/definitions/pkg_server_router.GetSchemaResponse' type: array type: object - pkg_server_router.PublishManifestRequest: - properties: - manifestId: - type: string - required: - - manifestId - type: object - pkg_server_router.PublishManifestResponse: - properties: - dwnResponse: - $ref: '#/definitions/dwn.PublishManifestResponse' - manifest: - $ref: '#/definitions/manifest.CredentialManifest' - required: - - dwnResponse - - manifest + pkg_server_router.Operation: type: object pkg_server_router.ResolveDIDResponse: properties: @@ -1354,7 +1378,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetHealthCheckResponse' + $ref: '#/definitions/pkg_server_router.GetHealthCheckResponse' summary: Health Check tags: - HealthCheck @@ -1655,36 +1679,6 @@ paths: summary: Resolve a DID tags: - DecentralizedIdentityAPI - /v1/dwn/manifest: - put: - consumes: - - application/json - description: Publish Manifest to DWN - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/pkg_server_router.PublishManifestRequest' - produces: - - application/json - responses: - "201": - description: Created - schema: - $ref: '#/definitions/pkg_server_router.PublishManifestResponse' - "400": - description: Bad request - schema: - type: string - "500": - description: Internal server error - schema: - type: string - summary: Publish Manifest to DWN - tags: - - DWNAPI /v1/keys: put: consumes: @@ -1696,7 +1690,7 @@ paths: name: request required: true schema: - $ref: '#/definitions/pkg_server_router.StoreKeyRequest' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.StoreKeyRequest' produces: - application/json responses: @@ -1730,7 +1724,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetKeyDetailsResponse' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetKeyDetailsResponse' "400": description: Bad request schema: @@ -2041,6 +2035,64 @@ paths: summary: Get response tags: - ResponseAPI + /v1/operations: + get: + consumes: + - application/json + description: Cancels an ongoing operation, if possible. + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.GetOperationsResponse' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Cancel an ongoing operation + tags: + - OperationAPI + /v1/operations/{id}: + get: + consumes: + - application/json + description: Get operation by its ID + parameters: + - description: ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/pkg_server_router.Operation' + "400": + description: Bad request + schema: + type: string + "500": + description: Internal server error + schema: + type: string + summary: Get an operation + tags: + - OperationAPI /v1/presentation/definition: put: consumes: @@ -2052,14 +2104,14 @@ paths: name: request required: true schema: - $ref: '#/definitions/pkg_server_router.CreatePresentationDefinitionRequest' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionRequest' produces: - application/json responses: "201": description: Created schema: - $ref: '#/definitions/pkg_server_router.CreatePresentationDefinitionResponse' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.CreatePresentationDefinitionResponse' "400": description: Bad request schema: @@ -2116,7 +2168,7 @@ paths: "200": description: OK schema: - $ref: '#/definitions/pkg_server_router.GetPresentationDefinitionResponse' + $ref: '#/definitions/github.com_tbd54566975_ssi-service_pkg_server_router.GetPresentationDefinitionResponse' "400": description: Bad request schema: diff --git a/pkg/server/router/operation.go b/pkg/server/router/operation.go new file mode 100644 index 000000000..a4dfb0bca --- /dev/null +++ b/pkg/server/router/operation.go @@ -0,0 +1,82 @@ +package router + +import ( + "context" + "fmt" + "github.com/pkg/errors" + svcframework "github.com/tbd54566975/ssi-service/pkg/service/framework" + "github.com/tbd54566975/ssi-service/pkg/service/operation" + "net/http" +) + +type OperationRouter struct { + service *operation.Service +} + +func NewOperationRouter(s svcframework.Service) (*OperationRouter, error) { + if s == nil { + return nil, errors.New("service cannot be nil") + } + service, ok := s.(*operation.Service) + if !ok { + return nil, fmt.Errorf("casting service: %s", s.Type()) + } + return &OperationRouter{service: service}, nil +} + +type Operation struct { +} + +// GetOperation godoc +// @Summary Get an operation +// @Description Get operation by its ID +// @Tags OperationAPI +// @Accept json +// @Produce json +// @Param id path string true "ID" +// @Success 200 {object} Operation "OK" +// @Failure 400 {string} string "Bad request" +// @Failure 500 {string} string "Internal server error" +// @Router /v1/operations/{id} [get] +func (pdr OperationRouter) GetOperation(ctx context.Context, w http.ResponseWriter, r *http.Request) error { + return nil +} + +type GetOperationsRequest struct { + Parent string `json:"parent"` + Filter string `json:"filter"` +} + +type GetOperationsResponse struct { + Operations []Operation `json:"operations"` +} + +// GetOperations godoc +// @Summary List operations +// @Description List operations according to the request +// @Tags OperationAPI +// @Accept json +// @Produce json +// @Param request body GetOperationsRequest true "request body" +// @Success 200 {object} GetOperationsResponse "OK" +// @Failure 400 {string} string "Bad request" +// @Failure 500 {string} string "Internal server error" +// @Router /v1/operations [get] +func (pdr OperationRouter) GetOperations(ctx context.Context, w http.ResponseWriter, r *http.Request) error { + return nil +} + +// CancelOperation godoc +// @Summary Cancel an ongoing operation +// @Description Cancels an ongoing operation, if possible. +// @Tags OperationAPI +// @Accept json +// @Produce json +// @Param id path string true "ID" +// @Success 200 {object} GetOperationsResponse "OK" +// @Failure 400 {string} string "Bad request" +// @Failure 500 {string} string "Internal server error" +// @Router /v1/operations [get] +func (pdr OperationRouter) CancelOperation(ctx context.Context, w http.ResponseWriter, r *http.Request) error { + return nil +} diff --git a/pkg/server/server.go b/pkg/server/server.go index ed6697a98..049d1f862 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -23,6 +23,7 @@ const ( HealthPrefix = "/health" ReadinessPrefix = "/readiness" V1Prefix = "/v1" + OperationPrefix = "/operations" DIDsPrefix = "/dids" SchemasPrefix = "/schemas" CredentialsPrefix = "/credentials" @@ -101,6 +102,8 @@ func (s *SSIServer) instantiateRouter(service svcframework.Service) error { return s.ManifestAPI(service) case svcframework.Presentation: return s.PresentationAPI(service) + case svcframework.Operation: + return s.OperationAPI(service) default: return fmt.Errorf("could not instantiate API for service: %s", serviceType) } @@ -182,6 +185,21 @@ func (s *SSIServer) KeyStoreAPI(service svcframework.Service) (err error) { return } +func (s *SSIServer) OperationAPI(service svcframework.Service) (err error) { + operationRouter, err := router.NewOperationRouter(service) + if err != nil { + return util.LoggingErrorMsg(err, "creating operation router") + } + + handlerPath := V1Prefix + OperationPrefix + + s.Handle(http.MethodGet, path.Join(handlerPath, "/:id"), operationRouter.GetOperation) + s.Handle(http.MethodGet, handlerPath, operationRouter.GetOperations) + s.Handle(http.MethodPut, path.Join(handlerPath, "/:id/cancel"), operationRouter.CancelOperation) + + return +} + func (s *SSIServer) ManifestAPI(service svcframework.Service) (err error) { manifestRouter, err := router.NewManifestRouter(service) if err != nil { diff --git a/pkg/service/framework/framework.go b/pkg/service/framework/framework.go index d357e3ebb..8d1e9bd49 100644 --- a/pkg/service/framework/framework.go +++ b/pkg/service/framework/framework.go @@ -14,6 +14,7 @@ const ( KeyStore Type = "keystore" Manifest Type = "manifest" Presentation Type = "presentation" + Operation Type = "operation" StatusReady StatusState = "ready" StatusNotReady StatusState = "not_ready" diff --git a/pkg/service/operation/service.go b/pkg/service/operation/service.go new file mode 100644 index 000000000..05a4b29e0 --- /dev/null +++ b/pkg/service/operation/service.go @@ -0,0 +1,45 @@ +package operation + +import ( + "fmt" + sdkutil "github.com/TBD54566975/ssi-sdk/util" + "github.com/pkg/errors" + "github.com/tbd54566975/ssi-service/internal/util" + "github.com/tbd54566975/ssi-service/pkg/service/framework" + opstorage "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" + "github.com/tbd54566975/ssi-service/pkg/storage" +) + +type Service struct { + storage opstorage.Storage +} + +func (s Service) Type() framework.Type { + return framework.Operation +} + +func (s Service) Status() framework.Status { + ae := sdkutil.NewAppendError() + if s.storage == nil { + ae.AppendString("no storage configured") + } + if !ae.IsEmpty() { + return framework.Status{ + Status: framework.StatusNotReady, + Message: fmt.Sprintf("operation service is not ready: %s", ae.Error().Error()), + } + } + return framework.Status{Status: framework.StatusReady} +} + +func NewOperationService(s storage.ServiceStorage) (*Service, error) { + opStorage, err := opstorage.NewOperationStorage(s) + if err != nil { + return nil, util.LoggingErrorMsg(err, "creating operation storage") + } + service := &Service{storage: opStorage} + if !service.Status().IsReady() { + return nil, errors.New(service.Status().Message) + } + return service, nil +} diff --git a/pkg/service/operation/storage/bolt.go b/pkg/service/operation/storage/bolt.go new file mode 100644 index 000000000..0198cfaee --- /dev/null +++ b/pkg/service/operation/storage/bolt.go @@ -0,0 +1,38 @@ +package storage + +import ( + "github.com/pkg/errors" + "github.com/tbd54566975/ssi-service/pkg/storage" +) + +type BoltOperationStorage struct { + db *storage.BoltDB +} + +func (b BoltOperationStorage) StoreOperation(op StoredOperation) error { + // TODO(andres) implement me + panic("implement me") +} + +func (b BoltOperationStorage) GetOperation(id string) (*StoredOperation, error) { + // TODO(andres) implement me + panic("implement me") +} + +func (b BoltOperationStorage) GetOperations() ([]StoredOperation, error) { + // TODO(andres) implement me + panic("implement me") +} + +func (b BoltOperationStorage) DeleteOperation(id string) error { + // TODO(andres) implement me + panic("implement me") +} + +func NewBoltOperationStorage(db *storage.BoltDB) (*BoltOperationStorage, error) { + if db == nil { + return nil, errors.New("bolt db reference is nil") + } + return &BoltOperationStorage{db: db}, nil + +} diff --git a/pkg/service/operation/storage/storage.go b/pkg/service/operation/storage/storage.go new file mode 100644 index 000000000..f5d94b4cd --- /dev/null +++ b/pkg/service/operation/storage/storage.go @@ -0,0 +1,36 @@ +package storage + +import ( + "github.com/tbd54566975/ssi-service/internal/util" + "github.com/tbd54566975/ssi-service/pkg/storage" +) + +type StoredOperation struct { + ID string `json:"id"` + Done bool `json:"done"` + Error string `json:"errorResult"` +} + +type Storage interface { + StoreOperation(op StoredOperation) error + GetOperation(id string) (*StoredOperation, error) + GetOperations() ([]StoredOperation, error) + DeleteOperation(id string) error +} + +func NewOperationStorage(s storage.ServiceStorage) (Storage, error) { + switch s.Type() { + case storage.Bolt: + gotBolt, ok := s.(*storage.BoltDB) + if !ok { + return nil, util.LoggingNewErrorf("trouble instantiating : %s", s.Type()) + } + boltStorage, err := NewBoltOperationStorage(gotBolt) + if err != nil { + return nil, util.LoggingErrorMsg(err, "could not instantiate schema bolt storage") + } + return boltStorage, err + default: + return nil, util.LoggingNewErrorf("unsupported storage type: %s", s.Type()) + } +} diff --git a/pkg/service/service.go b/pkg/service/service.go index 7e30f9b0d..635522558 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -2,6 +2,7 @@ package service import ( "fmt" + "github.com/tbd54566975/ssi-service/pkg/service/operation" "github.com/tbd54566975/ssi-service/pkg/service/presentation" "github.com/tbd54566975/ssi-service/config" @@ -101,5 +102,10 @@ func instantiateServices(config config.ServicesConfig) ([]framework.Service, err return nil, util.LoggingErrorMsg(err, "could not instantiate the presentation service") } - return []framework.Service{keyStoreService, didService, schemaService, credentialService, manifestService, presentationService}, nil + operationService, err := operation.NewOperationService(storageProvider) + if err != nil { + return nil, util.LoggingErrorMsg(err, "could not instantiate the operation service") + } + + return []framework.Service{keyStoreService, didService, schemaService, credentialService, manifestService, presentationService, operationService}, nil }