diff --git a/config/config.go b/config/config.go index 90bd8a9da..15ee22095 100644 --- a/config/config.go +++ b/config/config.go @@ -64,17 +64,6 @@ type ServerConfig struct { EnableAllowAllCORS bool `toml:"enable_allow_all_cors" conf:"default:false"` } -type IssuanceServiceConfig struct { - *BaseServiceConfig -} - -func (s *IssuanceServiceConfig) IsEmpty() bool { - if s == nil { - return true - } - return reflect.DeepEqual(s, &IssuanceServiceConfig{}) -} - // ServicesConfig represents configurable properties for the components of the SSI Service type ServicesConfig struct { // at present, it is assumed that a single storage provider works for all services @@ -87,11 +76,12 @@ 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"` - IssuanceServiceConfig IssuanceServiceConfig `toml:"issuance,omitempty"` SchemaConfig SchemaServiceConfig `toml:"schema,omitempty"` CredentialConfig CredentialServiceConfig `toml:"credential,omitempty"` - ManifestConfig ManifestServiceConfig `toml:"manifest,omitempty"` + OperationConfig OperationServiceConfig `toml:"operation,omitempty"` PresentationConfig PresentationServiceConfig `toml:"presentation,omitempty"` + ManifestConfig ManifestServiceConfig `toml:"manifest,omitempty"` + IssuanceServiceConfig IssuanceServiceConfig `toml:"issuance,omitempty"` WebhookConfig WebhookServiceConfig `toml:"webhook,omitempty"` } @@ -164,16 +154,15 @@ func (c *CredentialServiceConfig) IsEmpty() bool { return reflect.DeepEqual(c, &CredentialServiceConfig{}) } -type ManifestServiceConfig struct { +type OperationServiceConfig struct { *BaseServiceConfig - ExpirationDuration time.Duration `toml:"expiration_duration" conf:"default:30m"` } -func (m *ManifestServiceConfig) IsEmpty() bool { - if m == nil { +func (o *OperationServiceConfig) IsEmpty() bool { + if o == nil { return true } - return reflect.DeepEqual(m, &ManifestServiceConfig{}) + return reflect.DeepEqual(o, &OperationServiceConfig{}) } type PresentationServiceConfig struct { @@ -188,6 +177,29 @@ func (p *PresentationServiceConfig) IsEmpty() bool { return reflect.DeepEqual(p, &PresentationServiceConfig{}) } +type ManifestServiceConfig struct { + *BaseServiceConfig + ExpirationDuration time.Duration `toml:"expiration_duration" conf:"default:30m"` +} + +func (m *ManifestServiceConfig) IsEmpty() bool { + if m == nil { + return true + } + return reflect.DeepEqual(m, &ManifestServiceConfig{}) +} + +type IssuanceServiceConfig struct { + *BaseServiceConfig +} + +func (s *IssuanceServiceConfig) IsEmpty() bool { + if s == nil { + return true + } + return reflect.DeepEqual(s, &IssuanceServiceConfig{}) +} + type WebhookServiceConfig struct { *BaseServiceConfig WebhookTimeout string `toml:"webhook_timeout"` @@ -215,7 +227,8 @@ func LoadConfig(path string) (*SSIServiceConfig, error) { } if loadDefaultConfig { - loadDefaultServicesConfig(&config) + defaultServicesConfig := getDefaultServicesConfig() + config.Services = defaultServicesConfig } else if err = loadTOMLConfig(path, &config); err != nil { return nil, errors.Wrap(err, "load toml config") } @@ -236,74 +249,73 @@ func checkValidConfigPath(path string) (bool, error) { } else if filepath.Ext(path) != Extension { return false, fmt.Errorf("path<%s> did not match the expected TOML format", path) } - return defaultConfig, nil } func parseAndApplyDefaults(config SSIServiceConfig) error { // parse and apply defaults - if err := conf.Parse(os.Args[1:], ServiceName, &config); err != nil { - switch { - case errors.Is(err, conf.ErrHelpWanted): - usage, err := conf.Usage(ServiceName, &config) - if err != nil { - return errors.Wrap(err, "parsing config") - } - fmt.Println(usage) - - return nil - - case errors.Is(err, conf.ErrVersionWanted): - version, err := conf.VersionString(ServiceName, &config) - if err != nil { - return errors.Wrap(err, "generating config version") - } + err := conf.Parse(os.Args[1:], ServiceName, &config) + if err == nil { + return nil + } + switch { + case errors.Is(err, conf.ErrHelpWanted): + usage, err := conf.Usage(ServiceName, &config) + if err != nil { + return errors.Wrap(err, "parsing config") + } + logrus.Println(usage) - fmt.Println(version) - return nil + return nil + case errors.Is(err, conf.ErrVersionWanted): + version, err := conf.VersionString(ServiceName, &config) + if err != nil { + return errors.Wrap(err, "generating config version") } - return errors.Wrap(err, "parsing config") + logrus.Println(version) + return nil } - - return nil + return errors.Wrap(err, "parsing config") } -func loadDefaultServicesConfig(config *SSIServiceConfig) { - servicesConfig := ServicesConfig{ +// TODO(gabe) remove this from config in https://github.com/TBD54566975/ssi-service/issues/502 +func getDefaultServicesConfig() ServicesConfig { + return ServicesConfig{ StorageProvider: "bolt", ServiceEndpoint: DefaultServiceEndpoint, KeyStoreConfig: KeyStoreServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "keystore"}, + BaseServiceConfig: &BaseServiceConfig{Name: "keystore", ServiceEndpoint: DefaultServiceEndpoint + "/v1/keys"}, MasterKeyPassword: "default-password", }, DIDConfig: DIDServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "did"}, + BaseServiceConfig: &BaseServiceConfig{Name: "did", ServiceEndpoint: DefaultServiceEndpoint + "/v1/dids"}, Methods: []string{"key", "web"}, - LocalResolutionMethods: []string{"key", "peer", "web", "pkh"}, + LocalResolutionMethods: []string{"key", "peer", "web", "jwk", "pkh"}, }, SchemaConfig: SchemaServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "schema"}, + BaseServiceConfig: &BaseServiceConfig{Name: "schema", ServiceEndpoint: DefaultServiceEndpoint + "/v1/schemas"}, }, CredentialConfig: CredentialServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "credential", ServiceEndpoint: DefaultServiceEndpoint}, + BaseServiceConfig: &BaseServiceConfig{Name: "credential", ServiceEndpoint: DefaultServiceEndpoint + "/v1/credentials"}, }, - ManifestConfig: ManifestServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "manifest"}, + OperationConfig: OperationServiceConfig{ + BaseServiceConfig: &BaseServiceConfig{Name: "operation", ServiceEndpoint: DefaultServiceEndpoint + "/v1/operations"}, }, PresentationConfig: PresentationServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "presentation"}, + BaseServiceConfig: &BaseServiceConfig{Name: "presentation", ServiceEndpoint: DefaultServiceEndpoint + "/v1/presentations"}, + }, + ManifestConfig: ManifestServiceConfig{ + BaseServiceConfig: &BaseServiceConfig{Name: "manifest", ServiceEndpoint: DefaultServiceEndpoint + "/v1/manifests"}, }, IssuanceServiceConfig: IssuanceServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "issuance"}, + BaseServiceConfig: &BaseServiceConfig{Name: "issuance", ServiceEndpoint: DefaultServiceEndpoint + "/v1/issuancetemplates"}, }, WebhookConfig: WebhookServiceConfig{ - BaseServiceConfig: &BaseServiceConfig{Name: "webhook"}, + BaseServiceConfig: &BaseServiceConfig{Name: "webhook", ServiceEndpoint: DefaultServiceEndpoint + "/v1/webhooks"}, WebhookTimeout: "10s", }, } - - config.Services = servicesConfig } func loadTOMLConfig(path string, config *SSIServiceConfig) error { @@ -312,11 +324,63 @@ func loadTOMLConfig(path string, config *SSIServiceConfig) error { return errors.Wrapf(err, "could not load config: %s", path) } - // apply defaults if not included in toml file - if config.Services.CredentialConfig.BaseServiceConfig.ServiceEndpoint == "" { - config.Services.CredentialConfig.BaseServiceConfig.ServiceEndpoint = config.Services.ServiceEndpoint + // apply defaults + services := config.Services + endpoint := services.ServiceEndpoint + "/v1" + if services.KeyStoreConfig.IsEmpty() { + services.KeyStoreConfig = KeyStoreServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } } - + services.KeyStoreConfig.ServiceEndpoint = endpoint + "/keys" + if services.DIDConfig.IsEmpty() { + services.DIDConfig = DIDServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } + } + services.DIDConfig.ServiceEndpoint = endpoint + "/dids" + if services.SchemaConfig.IsEmpty() { + services.SchemaConfig = SchemaServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } + } + services.SchemaConfig.ServiceEndpoint = endpoint + "/schemas" + if services.CredentialConfig.IsEmpty() { + services.CredentialConfig = CredentialServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } + } + services.CredentialConfig.ServiceEndpoint = endpoint + "/credentials" + if services.OperationConfig.IsEmpty() { + services.OperationConfig = OperationServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } + } + services.OperationConfig.ServiceEndpoint = endpoint + "/operations" + if services.PresentationConfig.IsEmpty() { + services.PresentationConfig = PresentationServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } + } + services.PresentationConfig.ServiceEndpoint = endpoint + "/presentations" + if services.ManifestConfig.IsEmpty() { + services.ManifestConfig = ManifestServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } + } + services.ManifestConfig.ServiceEndpoint = endpoint + "/manifests" + if services.IssuanceServiceConfig.IsEmpty() { + services.IssuanceServiceConfig = IssuanceServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } + } + services.IssuanceServiceConfig.ServiceEndpoint = endpoint + "/issuancetemplates" + if services.WebhookConfig.IsEmpty() { + services.WebhookConfig = WebhookServiceConfig{ + BaseServiceConfig: new(BaseServiceConfig), + } + } + services.WebhookConfig.ServiceEndpoint = endpoint + "/webhooks" return nil } diff --git a/doc/docs.go b/doc/docs.go index 4edd61fe2..c21a7e846 100644 --- a/doc/docs.go +++ b/doc/docs.go @@ -5,7 +5,7 @@ package doc import "github.com/swaggo/swag/v2" const docTemplate = `{ - "schemes": {{ marshal .Schemes }},"swagger":"2.0","info":{"description":"{{escape .Description}}","title":"{{.Title}}","contact":{"name":"TBD","url":"https://github.com/TBD54566975/ssi-service/issues","email":"tbd-developer@squareup.com"},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"},"version":"{{.Version}}"},"host":"{{.Host}}","basePath":"{{.BasePath}}","paths":{"/health":{"get":{"description":"Health is a simple handler that always responds with a 200 OK","consumes":["application/json"],"produces":["application/json"],"tags":["HealthCheck"],"summary":"Health Check","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetHealthCheckResponse"}}}}},"/readiness":{"get":{"description":"Readiness runs a number of application specific checks to see if all the relied upon services are\nhealthy.","consumes":["application/json"],"produces":["application/json"],"tags":["Readiness"],"summary":"Readiness","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetReadinessResponse"}}}}},"/v1/credentials":{"get":{"description":"Checks for the presence of a query parameter and calls the associated filtered get method. Only one parameter is allowed to be specified.","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"List Credentials","parameters":[{"type":"string","example":"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp","description":"The issuer id","name":"issuer","in":"query"},{"type":"string","description":"The credentialSchema.id value to filter by","name":"schema","in":"query"},{"type":"string","description":"The credentialSubject.id value to filter by","name":"subject","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListCredentialsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create a verifiable credential","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Create Credential","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateCredentialRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateCredentialResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/credentials/status/{id}":{"get":{"description":"Get credential status list by id.","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Get Credential Status List","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetCredentialStatusListResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/credentials/verification":{"put":{"description":"Verify a given credential by its id. The system does the following levels of verification:\n1. Makes sure the credential has a valid signature\n2. Makes sure the credential has is not expired\n3. Makes sure the credential complies with the VC Data Model\n4. If the credential has a schema, makes sure its data complies with the schema","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Verify Credential","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.VerifyCredentialRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.VerifyCredentialResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/credentials/{id}":{"get":{"description":"Get credential by id","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Get Credential","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetCredentialResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"delete":{"description":"Delete credential by ID","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Delete Credentials","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/credentials/{id}/status":{"get":{"description":"Get credential status by id","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Get Credential Status","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetCredentialStatusResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Update a credential's status","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Update Credential Status","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.UpdateCredentialStatusRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.UpdateCredentialStatusResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/dids":{"get":{"description":"Get the list of supported DID methods","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"List DID Methods","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListDIDMethodsResponse"}}}}},"/v1/dids/resolver/{id}":{"get":{"description":"Resolve a DID that may not be stored in this service","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"Resolve a DID","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ResolveDIDResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}}},"/v1/dids/{method}":{"get":{"description":"List DIDs by method. Checks for an optional \"deleted=true\" query parameter, which exclusively returns DIDs that have been \"Soft Deleted\".","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"List DIDs","parameters":[{"type":"boolean","description":"When true, returns soft-deleted DIDs. Otherwise, returns DIDs that have not been soft-deleted. Default is false.","name":"deleted","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListDIDsByMethodResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Creates a fully custodial DID document with the given method. The document created is stored internally\nand can be retrieved using the GetOperation. Method dependent registration (for example, DID web\nregistration) is left up to the clients of this API. The private key(s) created by the method are stored\ninternally never leave the service boundary.","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"Create DID Document","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateDIDByMethodRequest"}},{"type":"string","description":"Method","name":"method","in":"path","required":true}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateDIDByMethodResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/dids/{method}/{id}":{"get":{"description":"Get DID by method","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"Get DID","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateDIDByMethodRequest"}},{"type":"string","description":"Method","name":"method","in":"path","required":true},{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetDIDByMethodResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"When this is called with the correct did method and id it will flip the softDelete flag to true for the db entry.\nA user can still get the did if they know the DID ID, and the did keys will still exist, but this did will not show up in the ListDIDsByMethod call\nThis facilitates a clean SSI-Service Admin UI but not leave any hanging VCs with inaccessible hanging DIDs.\nSoft Deletes DID by method","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"Soft Delete DID","parameters":[{"type":"string","description":"Method","name":"method","in":"path","required":true},{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/issuancetemplates":{"put":{"description":"Create issuance template","consumes":["application/json"],"produces":["application/json"],"tags":["IssuanceAPI"],"summary":"Create issuance template","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateIssuanceTemplateRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.Template"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/issuancetemplates/{id}":{"get":{"description":"Get an issuance template by its id","consumes":["application/json"],"produces":["application/json"],"tags":["IssuanceAPI"],"summary":"Get issuance template","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.Template"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete issuance template by ID","consumes":["application/json"],"produces":["application/json"],"tags":["IssuanceAPI"],"summary":"Delete issuance template","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/keys":{"put":{"description":"Stores a key to be used by the service","consumes":["application/json"],"produces":["application/json"],"tags":["KeyStoreAPI"],"summary":"Store Key","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.StoreKeyRequest"}}],"responses":{"201":{"description":"Created"},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/keys/{id}":{"get":{"description":"Get details about a stored key","consumes":["application/json"],"produces":["application/json"],"tags":["KeyStoreAPI"],"summary":"Get Details For Key","parameters":[{"type":"string","description":"ID of the key to get","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetKeyDetailsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Marks the stored key as being revoked, along with the timestamps of when it was revoked. NB: the key can still be used for signing. This will likely be addressed before v1 is released.","consumes":["application/json"],"produces":["application/json"],"tags":["KeyStoreAPI"],"summary":"Revoke Key","parameters":[{"type":"string","description":"ID of the key to revoke","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.RevokeKeyResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests":{"get":{"description":"Checks for the presence of a query parameter and calls the associated filtered get method","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"List manifests","parameters":[{"type":"string","description":"string issuer","name":"issuer","in":"query"},{"type":"string","description":"string schema","name":"schema","in":"query"},{"type":"string","description":"string subject","name":"subject","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListManifestsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create manifest","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Create manifest","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateManifestRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateManifestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/applications":{"get":{"description":"List all the existing applications.","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"List applications","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListApplicationsResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Submit a credential application in response to a credential manifest. The request body is expected to","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"Submit application","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.SubmitApplicationRequest"}}],"responses":{"201":{"description":"Operation with a SubmitApplicationResponse type in the ` + "`" + `result.response` + "`" + ` field.","schema":{"$ref":"#/definitions/pkg_server_router.Operation"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/applications/{id}":{"get":{"description":"Get application by id","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"Get application","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetApplicationResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete application by ID","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"Delete applications","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/applications/{id}/review":{"put":{"description":"Reviewing an application either fulfills or denies the credential.","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"Reviews an application","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.ReviewApplicationRequest"}}],"responses":{"201":{"description":"Credential Response","schema":{"$ref":"#/definitions/pkg_server_router.SubmitApplicationResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/requests":{"get":{"description":"Lists all the existing credential manifest requests","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"List Credential Manifest Requests","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListManifestRequestsResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create manifest request from an existing credential manifest.","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Create Manifest Request Request","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateManifestRequestRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateManifestRequestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/requests/{id}":{"get":{"description":"Get a manifest request by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Get Manifest Request","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetManifestRequestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete a manifest request by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Delete Manifest Request","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/responses":{"get":{"description":"Lists all responses","consumes":["application/json"],"produces":["application/json"],"tags":["ResponseAPI"],"summary":"List responses","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListResponsesResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/responses/{id}":{"get":{"description":"Get response by id","consumes":["application/json"],"produces":["application/json"],"tags":["ResponseAPI"],"summary":"Get response","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetResponseResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"delete":{"description":"Delete response by ID","consumes":["application/json"],"produces":["application/json"],"tags":["ResponseAPI"],"summary":"Delete responses","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/{id}":{"get":{"description":"Get a credential manifest by its id","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Get manifest","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListManifestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete manifest by ID","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Delete manifests","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/operations":{"get":{"description":"List operations according to the request","consumes":["application/json"],"produces":["application/json"],"tags":["OperationAPI"],"summary":"List operations","parameters":[{"type":"string","description":"The name of the parent's resource. For example: ` + "`" + `?parent=/presentation/submissions` + "`" + `","name":"parent","in":"query"},{"type":"string","description":"A standard filter expression conforming to https://google.aip.dev/160. For example: ` + "`" + `?filter=done=","name":"filter","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListOperationsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/operations/cancel/{id}":{"get":{"description":"Cancels an ongoing operation, if possible.","consumes":["application/json"],"produces":["application/json"],"tags":["OperationAPI"],"summary":"Cancel an ongoing operation","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"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"}}}}},"/v1/operations/{id}":{"get":{"description":"Get operation by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["OperationAPI"],"summary":"Get an operation","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"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"}}}}},"/v1/presentations/definitions":{"get":{"description":"Lists all the existing presentation definitions","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationDefinitionAPI"],"summary":"List Presentation Definitions","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListDefinitionsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create presentation definition","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationDefinitionAPI"],"summary":"Create PresentationDefinition","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreatePresentationDefinitionRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreatePresentationDefinitionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/definitions/{id}":{"get":{"description":"Get a presentation definition by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationDefinitionAPI"],"summary":"Get PresentationDefinition","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetPresentationDefinitionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete a presentation definition by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationDefinitionAPI"],"summary":"Delete PresentationDefinition","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/requests":{"put":{"description":"Create presentation request from an existing presentation definition.","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationRequestAPI"],"summary":"Create Presentation Request","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateRequestRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateRequestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/requests/{id}":{"get":{"description":"Get a presentation request by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationRequestAPI"],"summary":"Get Presentation Request","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetRequestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete a presentation request by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationRequestAPI"],"summary":"Delete PresentationRequest","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/submissions":{"get":{"description":"List existing submissions according to a filtering query. The ` + "`" + `filter` + "`" + ` field follows the syntax described in https://google.aip.dev/160.","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationSubmissionAPI"],"summary":"List Submissions","parameters":[{"type":"string","description":"A standard filter expression conforming to https://google.aip.dev/160. For example: ` + "`" + `?filter=status=","name":"filter","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListSubmissionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Creates a submission in this server ready to be reviewed.","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationSubmissionAPI"],"summary":"Create Submission","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateSubmissionRequest"}}],"responses":{"201":{"description":"The type of response is Submission once the operation has finished.","schema":{"$ref":"#/definitions/pkg_server_router.Operation"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/submissions/{id}":{"get":{"description":"Get a submission by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationSubmissionAPI"],"summary":"Get Submission","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetSubmissionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}}},"/v1/presentations/submissions/{id}/review":{"put":{"description":"Reviews a pending submission. After this method is called, the operation with ` + "`" + `id==presentations/submissions/{submission_id}` + "`" + ` will be updated with the result of this invocation.","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationSubmissionAPI"],"summary":"Review a pending submission","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.ReviewSubmissionRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ReviewSubmissionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/schemas":{"get":{"description":"List schemas","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"List Schemas","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListSchemasResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create schema","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"Create SchemaID","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateSchemaRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateSchemaResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/schemas/verification":{"put":{"description":"Verify a given schema by its id","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"Verify SchemaID","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.VerifySchemaRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.VerifySchemaResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}}},"/v1/schemas/{id}":{"get":{"description":"Get a schema by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"Get SchemaID","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetSchemaResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete a schema by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"Delete SchemaID","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/webhooks":{"get":{"description":"Lists all webhooks","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"List Webhooks","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListWebhooksResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create webhook","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Create Webhook","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateWebhookRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateWebhookResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/webhooks/nouns":{"get":{"description":"Get supported nouns for webhook generation","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Get Supported Nouns","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.GetSupportedNounsResponse"}}}}},"/v1/webhooks/verbs":{"get":{"description":"Get supported verbs for webhook generation","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Get Supported Verbs","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.GetSupportedVerbsResponse"}}}}},"/v1/webhooks/{noun}/{verb}":{"get":{"description":"Get a webhook by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Get Webhook","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListWebhookResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}}},"/v1/webhooks/{noun}/{verb}/{url}":{"delete":{"description":"Delete a webhook by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Delete Webhook","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}}},"definitions":{"credential.CredentialSchema":{"type":"object","required":["id","type"],"properties":{"id":{"type":"string"},"type":{"type":"string"}}},"credential.CredentialSubject":{"type":"object","additionalProperties":{}},"credential.Prohibition":{"type":"object","properties":{"action":{"type":"array","items":{"type":"string"}},"assignee":{"type":"string"},"assigner":{"type":"string"},"target":{"type":"string"}}},"credential.RefreshService":{"type":"object","required":["id","type"],"properties":{"id":{"type":"string"},"type":{"type":"string"}}},"credential.TermsOfUse":{"type":"object","properties":{"id":{"type":"string"},"profile":{"type":"string"},"prohibition":{"type":"array","items":{"$ref":"#/definitions/credential.Prohibition"}},"type":{"type":"string"}}},"credential.VerifiableCredential":{"type":"object","required":["@context","credentialSubject","issuanceDate","issuer","type"],"properties":{"@context":{"description":"Either a string or set of strings"},"credentialSchema":{"$ref":"#/definitions/credential.CredentialSchema"},"credentialStatus":{},"credentialSubject":{"description":"This is where the subject's ID *may* be present","allOf":[{"$ref":"#/definitions/credential.CredentialSubject"}]},"evidence":{"type":"array","items":{}},"expirationDate":{"type":"string"},"id":{"type":"string"},"issuanceDate":{"description":"https://www.w3.org/TR/xmlschema11-2/#dateTimes","type":"string"},"issuer":{"description":"either a URI or an object containing an ` + "`" + `id` + "`" + ` property."},"proof":{"description":"For embedded proof support\nProof is a digital signature over a credential https://www.w3.org/TR/2021/REC-vc-data-model-20211109/#proofs-signatures"},"refreshService":{"$ref":"#/definitions/credential.RefreshService"},"termsOfUse":{"type":"array","items":{"$ref":"#/definitions/credential.TermsOfUse"}},"type":{"description":"Either a string or a set of strings https://www.w3.org/TR/2021/REC-vc-data-model-20211109/#types"}}},"credential.VerifiablePresentation":{"type":"object","required":["type"],"properties":{"@context":{"description":"Either a string or set of strings"},"holder":{"type":"string"},"id":{"type":"string"},"presentation_submission":{"description":"an optional field as a part of https://identity.foundation/presentation-exchange/#embed-targets"},"proof":{},"type":{},"verifiableCredential":{"description":"Verifiable credential could be our object model, a JWT, or any other valid credential representation","type":"array","items":{}}}},"crypto.KeyType":{"type":"string","enum":["Ed25519","X25519","secp256k1","secp256k1-ECDSA","P-224","P-256","P-384","P-521","RSA","Dilithium2","Dilithium3","Dilithium5"],"x-enum-varnames":["Ed25519","X25519","SECP256k1","SECP256k1ECDSA","P224","P256","P384","P521","RSA","Dilithium2","Dilithium3","Dilithium5"]},"crypto.SignatureAlgorithm":{"type":"string","enum":["EdDSA","ES256K","ES256","ES384","PS256","Dilithium2","Dilithium3","Dilithium5"],"x-enum-varnames":["EdDSA","ES256K","ES256","ES384","PS256","Dilithium2Sig","Dilithium3Sig","Dilithium5Sig"]},"did.Document":{"type":"object","properties":{"@context":{},"alsoKnownAs":{"type":"string"},"assertionMethod":{"type":"array","items":{}},"authentication":{"type":"array","items":{}},"capabilityDelegation":{"type":"array","items":{}},"capabilityInvocation":{"type":"array","items":{}},"controller":{"type":"string"},"id":{"description":"As per https://www.w3.org/TR/did-core/#did-subject intermediate representations of DID Documents do not\nrequire an ID property. The provided test vectors demonstrate IRs. As such, the property is optional.","type":"string"},"keyAgreement":{"type":"array","items":{}},"service":{"type":"array","items":{"$ref":"#/definitions/github_com_TBD54566975_ssi-sdk_did.Service"}},"verificationMethod":{"type":"array","items":{"$ref":"#/definitions/did.VerificationMethod"}}}},"did.Method":{"type":"string","enum":["key","peer","pkh","web","ion","jwk"],"x-enum-varnames":["KeyMethod","PeerMethod","PKHMethod","WebMethod","IONMethod","JWKMethod"]},"did.VerificationMethod":{"type":"object","required":["controller","id","type"],"properties":{"blockchainAccountId":{"description":"for PKH DIDs - https://github.com/w3c-ccg/did-pkh/blob/90b28ad3c18d63822a8aab3c752302aa64fc9382/did-pkh-method-draft.md","type":"string"},"controller":{"type":"string"},"id":{"type":"string"},"publicKeyBase58":{"type":"string"},"publicKeyJwk":{"description":"must conform to https://datatracker.ietf.org/doc/html/rfc7517","allOf":[{"$ref":"#/definitions/jwx.PublicKeyJWK"}]},"publicKeyMultibase":{"description":"https://datatracker.ietf.org/doc/html/draft-multiformats-multibase-03","type":"string"},"type":{"type":"string"}}},"exchange.ClaimFormat":{"type":"object","properties":{"jwt":{"$ref":"#/definitions/exchange.JWTType"},"jwt_vc":{"$ref":"#/definitions/exchange.JWTType"},"jwt_vp":{"$ref":"#/definitions/exchange.JWTType"},"ldp":{"$ref":"#/definitions/exchange.LDPType"},"ldp_vc":{"$ref":"#/definitions/exchange.LDPType"},"ldp_vp":{"$ref":"#/definitions/exchange.LDPType"}}},"exchange.Constraints":{"type":"object","properties":{"fields":{"type":"array","items":{"$ref":"#/definitions/exchange.Field"}},"is_holder":{"type":"array","items":{"$ref":"#/definitions/exchange.RelationalConstraint"}},"limit_disclosure":{"$ref":"#/definitions/exchange.Preference"},"same_subject":{"type":"array","items":{"$ref":"#/definitions/exchange.RelationalConstraint"}},"statuses":{"description":"https://identity.foundation/presentation-exchange/#credential-status-constraint-feature","allOf":[{"$ref":"#/definitions/exchange.CredentialStatus"}]},"subject_is_issuer":{"description":"https://identity.foundation/presentation-exchange/#relational-constraint-feature","allOf":[{"$ref":"#/definitions/exchange.Preference"}]}}},"exchange.CredentialStatus":{"type":"object","properties":{"active":{"type":"object","properties":{"directive":{"$ref":"#/definitions/exchange.Preference"}}},"revoked":{"type":"object","properties":{"directive":{"$ref":"#/definitions/exchange.Preference"}}},"suspended":{"type":"object","properties":{"directive":{"$ref":"#/definitions/exchange.Preference"}}}}},"exchange.Field":{"type":"object","required":["path"],"properties":{"filter":{"$ref":"#/definitions/exchange.Filter"},"id":{"type":"string"},"intent_to_retain":{"description":"https://identity.foundation/presentation-exchange/spec/v2.0.0/#retention-feature","type":"boolean"},"name":{"type":"string"},"optional":{"type":"boolean"},"path":{"type":"array","items":{"type":"string"}},"predicate":{"description":"If a predicate property is present, filter must be too\nhttps://identity.foundation/presentation-exchange/#predicate-feature","allOf":[{"$ref":"#/definitions/exchange.Preference"}]},"purpose":{"type":"string"}}},"exchange.Filter":{"type":"object","properties":{"additionalProperties":{"type":"boolean"},"allOf":{},"const":{},"enum":{"type":"array","items":{}},"exclusiveMaximum":{},"exclusiveMinimum":{},"format":{"type":"string"},"maxLength":{"type":"integer"},"maximum":{},"minLength":{"type":"integer"},"minimum":{},"not":{},"oneOf":{},"pattern":{"type":"string"},"properties":{},"required":{"type":"array","items":{"type":"string"}},"type":{"type":"string"}}},"exchange.InputDescriptor":{"type":"object","required":["constraints","id"],"properties":{"constraints":{"$ref":"#/definitions/exchange.Constraints"},"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"group":{"description":"Must match a grouping strings listed in the ` + "`" + `from` + "`" + ` values of a submission requirement rule","type":"array","items":{"type":"string"}},"id":{"description":"Must be unique within the Presentation Definition","type":"string"},"name":{"type":"string"},"purpose":{"description":"Purpose for which claim's data is being requested","type":"string"}}},"exchange.JWTType":{"type":"object","required":["alg"],"properties":{"alg":{"type":"array","items":{"$ref":"#/definitions/crypto.SignatureAlgorithm"}}}},"exchange.LDPType":{"type":"object","required":["proof_type"],"properties":{"proof_type":{"type":"array","items":{"type":"string"}}}},"exchange.Preference":{"type":"string","enum":["required","preferred","allowed","disallowed"],"x-enum-varnames":["Required","Preferred","Allowed","Disallowed"]},"exchange.PresentationDefinition":{"type":"object","required":["id","input_descriptors"],"properties":{"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"frame":{"description":"https://identity.foundation/presentation-exchange/#json-ld-framing-feature"},"id":{"type":"string"},"input_descriptors":{"type":"array","items":{"$ref":"#/definitions/exchange.InputDescriptor"}},"name":{"type":"string"},"purpose":{"type":"string"},"submission_requirements":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionRequirement"}}}},"exchange.PresentationSubmission":{"type":"object","required":["definition_id","descriptor_map","id"],"properties":{"definition_id":{"type":"string"},"descriptor_map":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionDescriptor"}},"id":{"type":"string"}}},"exchange.RelationalConstraint":{"type":"object","required":["directive","field_id"],"properties":{"directive":{"$ref":"#/definitions/exchange.Preference"},"field_id":{"type":"array","items":{"type":"string"}}}},"exchange.Selection":{"type":"string","enum":["all","pick"],"x-enum-varnames":["All","Pick"]},"exchange.SubmissionDescriptor":{"type":"object","required":["format","id","path"],"properties":{"format":{"type":"string"},"id":{"description":"Must match the ` + "`" + `id` + "`" + ` property of the corresponding input descriptor","type":"string"},"path":{"type":"string"},"path_nested":{"$ref":"#/definitions/exchange.SubmissionDescriptor"}}},"exchange.SubmissionRequirement":{"type":"object","required":["rule"],"properties":{"count":{"type":"integer","minimum":1},"from":{"type":"string"},"from_nested":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionRequirement"}},"max":{"type":"integer"},"min":{"type":"integer"},"name":{"type":"string"},"purpose":{"type":"string"},"rule":{"$ref":"#/definitions/exchange.Selection"}}},"github_com_TBD54566975_ssi-sdk_did.Service":{"type":"object","required":["id","serviceEndpoint","type"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"routingKeys":{"type":"array","items":{"type":"string"}},"serviceEndpoint":{"description":"A string, map, or set composed of one or more strings and/or maps\nAll string values must be valid URIs"},"type":{"type":"string"}}},"github_com_tbd54566975_ssi-service_internal_credential.Container":{"type":"object","properties":{"credential":{"$ref":"#/definitions/credential.VerifiableCredential"},"credentialJwt":{"type":"string"},"id":{"description":"Credential ID","type":"string"},"issuerKid":{"type":"string"},"revoked":{"type":"boolean"},"suspended":{"type":"boolean"}}},"github_com_tbd54566975_ssi-service_pkg_service_framework.Status":{"type":"object","properties":{"message":{"description":"When ` + "`" + `status` + "`" + ` is ` + "`" + `not_ready` + "`" + `, then message contains explanation of why it's not ready.","type":"string"},"status":{"description":"Either ` + "`" + `ready` + "`" + ` or ` + "`" + `not_ready` + "`" + `.","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_framework.StatusState"}]}}},"github_com_tbd54566975_ssi-service_pkg_service_framework.StatusState":{"type":"string","enum":["ready","not_ready"],"x-enum-varnames":["StatusReady","StatusNotReady"]},"github_com_tbd54566975_ssi-service_pkg_service_issuance.ClaimTemplates":{"type":"object","additionalProperties":{}},"github_com_tbd54566975_ssi-service_pkg_service_issuance.CredentialTemplate":{"type":"object","properties":{"credentialInputDescriptor":{"description":"Optional.\nWhen present, it's the ID of the input descriptor in the application. Corresponds to one of the\nPresentationDefinition.InputDescriptors[].ID in the credential manifest. When creating a credential, the base\ndata will be populated from the provided submission that matches this ID.\nWhen absent, there will be no base data for the credentials created. Additionally, no JSON path strings in\nClaimTemplates.Data will be resolved.","type":"string"},"data":{"description":"Data that will be used to determine credential claims.\nValues may be json path like strings, or any other JSON primitive. Each entry will be used to come up with a\nclaim about the credentialSubject in the credential that will be issued.","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.ClaimTemplates"}]},"expiry":{"description":"Parameter to determine the expiry of the credential.","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.TimeLike"}]},"id":{"description":"ID corresponding to an OutputDescriptor.ID from the manifest.","type":"string"},"revocable":{"description":"Whether the credentials created should be revocable.","type":"boolean"},"schema":{"description":"ID of the CredentialSchema to be used for the issued credential.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_issuance.Template":{"type":"object","required":["credentialManifest","issuer","issuerKid"],"properties":{"credentialManifest":{"description":"ID of the credential manifest that this template corresponds to.","type":"string"},"credentials":{"description":"Info required to create a credential from a credential application.","type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.CredentialTemplate"}},"id":{"description":"ID of this template.","type":"string"},"issuer":{"description":"ID of the issuer that will be issuance the credentials.","type":"string"},"issuerKid":{"description":"ID of the key that will be used to sign the credentials.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_issuance.TimeLike":{"type":"object","properties":{"duration":{"description":"For a fixed offset from when it was issued.","allOf":[{"$ref":"#/definitions/time.Duration"}]},"time":{"description":"For fixed time in the future.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_manifest_model.CredentialOverride":{"type":"object","properties":{"data":{"description":"Data that will be used to determine credential claims.","type":"object","additionalProperties":{}},"expiry":{"description":"Parameter to determine the expiry of the credential.","type":"string"},"revocable":{"description":"Whether the credentials created should be revocable.","type":"boolean"}}},"github_com_tbd54566975_ssi-service_pkg_service_manifest_model.Request":{"type":"object","required":["expiration","issuerId","issuerKid","manifestId"],"properties":{"audience":{"description":"Audience as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3.","type":"array","items":{"type":"string"}},"credentialManifestJwt":{"description":"CredentialManifestJWT is a JWT token with a \"presentation_definition\" claim within it. The\nvalue of the field named \"presentation_definition.id\" matches PresentationDefinitionID.\nThis is an output only field.","type":"string"},"expiration":{"description":"Expiration as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4","type":"string"},"id":{"description":"ID for this request. It matches the \"jti\" claim in the JWT.\nThis is an output only field.","type":"string"},"issuerId":{"description":"DID of the issuer of this presentation definition.","type":"string"},"issuerKid":{"description":"The privateKey associated with the KID used to sign the JWT.","type":"string"},"manifestId":{"description":"ID of the credential manifest used for this request.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Request":{"type":"object","required":["expiration","issuerId","issuerKid","presentationDefinitionId"],"properties":{"audience":{"description":"Audience as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3.","type":"array","items":{"type":"string"}},"expiration":{"description":"Expiration as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4","type":"string"},"id":{"description":"ID for this request. It matches the \"jti\" claim in the JWT.\nThis is an output only field.","type":"string"},"issuerId":{"description":"DID of the issuer of this presentation definition.","type":"string"},"issuerKid":{"description":"The privateKey associated with the KID used to sign the JWT.","type":"string"},"presentationDefinitionId":{"description":"ID of the presentation definition used for this request.","type":"string"},"presentationRequestJwt":{"description":"PresentationDefinitionJWT is a JWT token with a \"presentation_definition\" claim within it. The\nvalue of the field named \"presentation_definition.id\" matches PresentationDefinitionID.\nThis is an output only field.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission":{"type":"object","required":["status"],"properties":{"reason":{"description":"The reason why the submission was approved or denied.","type":"string"},"status":{"description":"One of {` + "`" + `pending` + "`" + `, ` + "`" + `approved` + "`" + `, ` + "`" + `denied` + "`" + `, ` + "`" + `cancelled` + "`" + `}.","type":"string"},"verifiablePresentation":{"description":"The verifiable presentation containing the presentation_submission along with the credentials presented.","allOf":[{"$ref":"#/definitions/credential.VerifiablePresentation"}]}}},"github_com_tbd54566975_ssi-service_pkg_service_webhook.GetSupportedNounsResponse":{"type":"object","properties":{"nouns":{"type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Noun"}}}},"github_com_tbd54566975_ssi-service_pkg_service_webhook.GetSupportedVerbsResponse":{"type":"object","properties":{"verbs":{"type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Verb"}}}},"github_com_tbd54566975_ssi-service_pkg_service_webhook.Noun":{"type":"string","enum":["Credential","DID","Manifest","SchemaID","Presentation","Application","Submission"],"x-enum-varnames":["Credential","DID","Manifest","Schema","Presentation","Application","Submission"]},"github_com_tbd54566975_ssi-service_pkg_service_webhook.Verb":{"type":"string","enum":["Create","Delete"],"x-enum-varnames":["Create","Delete"]},"github_com_tbd54566975_ssi-service_pkg_service_webhook.Webhook":{"type":"object","required":["noun","urls","verb"],"properties":{"noun":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Noun"},"urls":{"type":"array","items":{"type":"string"}},"verb":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Verb"}}},"jwx.PublicKeyJWK":{"type":"object","required":["kty"],"properties":{"alg":{"type":"string"},"crv":{"type":"string"},"e":{"type":"string"},"key_ops":{"type":"string"},"kid":{"type":"string"},"kty":{"type":"string"},"n":{"type":"string"},"use":{"type":"string"},"x":{"type":"string"},"y":{"type":"string"}}},"manifest.CredentialApplication":{"type":"object","required":["format","id","manifest_id","spec_version"],"properties":{"applicant":{"type":"string"},"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"id":{"type":"string"},"manifest_id":{"type":"string"},"presentation_submission":{"description":"Must be present if the corresponding manifest contains a presentation_definition","allOf":[{"$ref":"#/definitions/exchange.PresentationSubmission"}]},"spec_version":{"type":"string"}}},"manifest.CredentialManifest":{"type":"object","required":["id","issuer","output_descriptors","spec_version"],"properties":{"description":{"type":"string"},"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"id":{"type":"string"},"issuer":{"$ref":"#/definitions/manifest.Issuer"},"name":{"type":"string"},"output_descriptors":{"type":"array","items":{"$ref":"#/definitions/manifest.OutputDescriptor"}},"presentation_definition":{"$ref":"#/definitions/exchange.PresentationDefinition"},"spec_version":{"type":"string"}}},"manifest.CredentialResponse":{"type":"object","required":["id","manifest_id","spec_version"],"properties":{"applicant":{"type":"string"},"application_id":{"type":"string"},"denial":{"type":"object","required":["reason"],"properties":{"input_descriptors":{"type":"array","items":{"type":"string"}},"reason":{"type":"string"}}},"fulfillment":{"type":"object","required":["descriptor_map"],"properties":{"descriptor_map":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionDescriptor"}}}},"id":{"type":"string"},"manifest_id":{"type":"string"},"spec_version":{"type":"string"}}},"manifest.Issuer":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"styles":{"description":"an object or URI as defined by the DIF Entity Styles specification\nhttps://identity.foundation/wallet-rendering/#entity-styles","allOf":[{"$ref":"#/definitions/rendering.EntityStyleDescriptor"}]}}},"manifest.OutputDescriptor":{"type":"object","required":["id","schema"],"properties":{"description":{"type":"string"},"display":{"description":"both below: an object or URI as defined by the DIF Entity Styles specification","allOf":[{"$ref":"#/definitions/rendering.DataDisplay"}]},"id":{"description":"Must be unique within a manifest","type":"string"},"name":{"type":"string"},"schema":{"type":"string"},"styles":{"$ref":"#/definitions/rendering.EntityStyleDescriptor"}}},"pkg_server_router.CreateCredentialRequest":{"type":"object","required":["data","issuer","issuerKid","subject"],"properties":{"@context":{"description":"A context is optional. If not present, we'll apply default, required context values.","type":"string"},"data":{"description":"Claims about the subject. The keys should be predicates (e.g. \"alumniOf\"), and the values can be any object.","type":"object","additionalProperties":{"type":"string"},"example":{"alumniOf":"did_for_uni"}},"expiry":{"description":"Optional. Corresponds to ` + "`" + `expirationDate` + "`" + ` in https://www.w3.org/TR/vc-data-model/#expiration.","type":"string","example":"2020-01-01T19:23:24Z"},"issuer":{"description":"The issuer id.","type":"string","example":"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"},"issuerKid":{"description":"The KID used to sign the credential","type":"string","example":"#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"},"revocable":{"description":"Whether this credential can be revoked. When true, the created VC will have the \"credentialStatus\"\nproperty set.","type":"boolean"},"schemaId":{"description":"A schema ID is optional. If present, we'll attempt to look it up and validate the data against it.","type":"string"},"subject":{"description":"The subject id.","type":"string","example":"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"},"suspendable":{"description":"Whether this credential can be suspended. When true, the created VC will have the \"credentialStatus\"\nproperty set.","type":"boolean"}}},"pkg_server_router.CreateCredentialResponse":{"type":"object","properties":{"credential":{"description":"A verifiable credential conformant to the media type ` + "`" + `application/vc+ld+json` + "`" + `.","allOf":[{"$ref":"#/definitions/credential.VerifiableCredential"}]},"credentialJwt":{"description":"The same verifiable credential, but using the syntax defined for the media type ` + "`" + `application/vc+jwt` + "`" + `. See\nhttps://w3c.github.io/vc-jwt/ for more details.","type":"string"}}},"pkg_server_router.CreateDIDByMethodRequest":{"type":"object","required":["keyType"],"properties":{"keyType":{"description":"Identifies the cryptographic algorithm family to use when generating this key.\nOne of the following: \"Ed25519\", \"X25519\", \"secp256k1\", \"P-224\",\"P-256\",\"P-384\", \"P-521\", \"RSA\"","allOf":[{"$ref":"#/definitions/crypto.KeyType"}]},"options":{"description":"Options for creating the DID. Implementation dependent on the method."}}},"pkg_server_router.CreateDIDByMethodResponse":{"type":"object","properties":{"did":{"$ref":"#/definitions/did.Document"}}},"pkg_server_router.CreateIssuanceTemplateRequest":{"type":"object","required":["credentialManifest","issuer","issuerKid"],"properties":{"credentialManifest":{"description":"ID of the credential manifest that this template corresponds to.","type":"string"},"credentials":{"description":"Info required to create a credential from a credential application.","type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.CredentialTemplate"}},"id":{"description":"ID of this template.","type":"string"},"issuer":{"description":"ID of the issuer that will be issuance the credentials.","type":"string"},"issuerKid":{"description":"ID of the key that will be used to sign the credentials.","type":"string"}}},"pkg_server_router.CreateManifestRequest":{"type":"object","required":["format","issuerDid","issuerKid","outputDescriptors"],"properties":{"description":{"type":"string"},"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"issuerDid":{"type":"string"},"issuerKid":{"type":"string"},"issuerName":{"type":"string"},"name":{"type":"string"},"outputDescriptors":{"type":"array","items":{"$ref":"#/definitions/manifest.OutputDescriptor"}},"presentationDefinition":{"$ref":"#/definitions/exchange.PresentationDefinition"}}},"pkg_server_router.CreateManifestRequestRequest":{"type":"object","required":["credentialManifestId","issuerId","issuerKid"],"properties":{"audience":{"description":"Audience as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3\nOptional","type":"array","items":{"type":"string"}},"credentialManifestId":{"description":"ID of the credential manifest to use for this request.","type":"string"},"expiration":{"description":"Expiration as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4\nOptional. When not specified, the request will be valid for a default duration.","type":"string"},"issuerId":{"description":"DID of the issuer of this presentation definition. The DID must have been previously created with the DID API,\nor the PrivateKey must have been added independently.","type":"string"},"issuerKid":{"description":"The privateKey associated with the KID will be used to sign an envelope that contains\nthe created presentation definition.","type":"string"}}},"pkg_server_router.CreateManifestRequestResponse":{"type":"object","properties":{"manifestRequest":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_manifest_model.Request"}}},"pkg_server_router.CreateManifestResponse":{"type":"object","properties":{"credential_manifest":{"$ref":"#/definitions/manifest.CredentialManifest"}}},"pkg_server_router.CreatePresentationDefinitionRequest":{"type":"object","required":["inputDescriptors"],"properties":{"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"inputDescriptors":{"type":"array","items":{"$ref":"#/definitions/exchange.InputDescriptor"}},"name":{"type":"string"},"purpose":{"type":"string"},"submissionRequirements":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionRequirement"}}}},"pkg_server_router.CreatePresentationDefinitionResponse":{"type":"object","properties":{"presentationDefinitionJwt":{"description":"Signed envelope that contains the PresentationDefinition created using the privateKey of the author of the\ndefinition.","type":"string"},"presentation_definition":{"$ref":"#/definitions/exchange.PresentationDefinition"}}},"pkg_server_router.CreateRequestRequest":{"type":"object","required":["issuerId","issuerKid","presentationDefinitionId"],"properties":{"audience":{"description":"Audience as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3\nOptional","type":"array","items":{"type":"string"}},"expiration":{"description":"Expiration as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4\nOptional. When not specified, the request will be valid for a default duration.","type":"string"},"issuerId":{"description":"DID of the issuer of this presentation definition. The DID must have been previously created with the DID API,\nor the PrivateKey must have been added independently.","type":"string"},"issuerKid":{"description":"The privateKey associated with the KID will be used to sign an envelope that contains\nthe created presentation definition.","type":"string"},"presentationDefinitionId":{"description":"ID of the presentation definition to use for this request.","type":"string"}}},"pkg_server_router.CreateRequestResponse":{"type":"object","properties":{"presentationRequest":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Request"}}},"pkg_server_router.CreateSchemaRequest":{"type":"object","required":["author","name","schema"],"properties":{"author":{"type":"string"},"authorKid":{"description":"AuthorKID represents the KID of the author's private key to sign the schema. Required if sign is true.","type":"string"},"name":{"type":"string"},"schema":{"$ref":"#/definitions/schema.JSONSchema"},"sign":{"description":"Sign represents whether the schema should be signed by the author. Default is false.\nIf sign is true, the schema will be signed by the author's private key with the specified KID","type":"boolean"}}},"pkg_server_router.CreateSchemaResponse":{"type":"object","properties":{"id":{"type":"string"},"schema":{"$ref":"#/definitions/schema.VCJSONSchema"},"schemaJwt":{"type":"string"}}},"pkg_server_router.CreateSubmissionRequest":{"type":"object","required":["submissionJwt"],"properties":{"submissionJwt":{"description":"A Verifiable Presentation that's encoded as a JWT.\nVerifiable Presentation are described in https://www.w3.org/TR/vc-data-model/#presentations-0\nJWT encoding of the Presentation as described in https://www.w3.org/TR/vc-data-model/#presentations-0","type":"string"}}},"pkg_server_router.CreateWebhookRequest":{"type":"object","required":["noun","url","verb"],"properties":{"noun":{"description":"The noun (entity) for the new webhook.eg: Credential","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Noun"}]},"url":{"description":"The URL to post the output of this request to Noun.Verb action to.","type":"string"},"verb":{"description":"The verb for the new webhook.eg: Create","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Verb"}]}}},"pkg_server_router.CreateWebhookResponse":{"type":"object","properties":{"webhook":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Webhook"}}},"pkg_server_router.GetApplicationResponse":{"type":"object","properties":{"application":{"$ref":"#/definitions/manifest.CredentialApplication"},"id":{"type":"string"}}},"pkg_server_router.GetCredentialResponse":{"type":"object","properties":{"credential":{"$ref":"#/definitions/credential.VerifiableCredential"},"credentialJwt":{"type":"string"},"id":{"type":"string"}}},"pkg_server_router.GetCredentialStatusListResponse":{"type":"object","properties":{"credential":{"description":"Credential where type includes \"VerifiableCredential\" and \"StatusList2021\".","allOf":[{"$ref":"#/definitions/credential.VerifiableCredential"}]},"credentialJwt":{"description":"The JWT signed with the associated issuer's private key.","type":"string"},"id":{"type":"string"}}},"pkg_server_router.GetCredentialStatusResponse":{"type":"object","properties":{"revoked":{"description":"Whether the credential has been revoked.","type":"boolean"},"suspended":{"description":"Whether the credential has been suspended.","type":"boolean"}}},"pkg_server_router.GetDIDByMethodResponse":{"type":"object","properties":{"did":{"$ref":"#/definitions/did.Document"}}},"pkg_server_router.GetHealthCheckResponse":{"type":"object","properties":{"status":{"description":"Status is always equal to ` + "`" + `OK` + "`" + `.","type":"string"}}},"pkg_server_router.GetKeyDetailsResponse":{"type":"object","properties":{"controller":{"type":"string"},"createdAt":{"description":"Represents the time at which the key was created. Encoded according to RFC3339.","type":"string"},"id":{"type":"string"},"publicKeyJwk":{"description":"The public key in JWK format according to RFC7517. This public key is associated with the private\nkey with the associated ID.","allOf":[{"$ref":"#/definitions/jwx.PublicKeyJWK"}]},"type":{"$ref":"#/definitions/crypto.KeyType"}}},"pkg_server_router.GetManifestRequestResponse":{"type":"object","properties":{"manifestRequest":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_manifest_model.Request"}}},"pkg_server_router.GetPresentationDefinitionResponse":{"type":"object","properties":{"presentation_definition":{"$ref":"#/definitions/exchange.PresentationDefinition"}}},"pkg_server_router.GetReadinessResponse":{"type":"object","properties":{"serviceStatuses":{"description":"A map from the name of the service ot the status of that current service.","type":"object","additionalProperties":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_framework.Status"}},"status":{"description":"Overall status of the ssi service.","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_framework.Status"}]}}},"pkg_server_router.GetRequestResponse":{"type":"object","properties":{"presentationRequest":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Request"}}},"pkg_server_router.GetResponseResponse":{"type":"object","properties":{"credential_response":{"$ref":"#/definitions/manifest.CredentialResponse"},"responseJwt":{"type":"string"},"verifiableCredentials":{"description":"this is an interface type to union Data Integrity and JWT style VCs"}}},"pkg_server_router.GetSchemaResponse":{"type":"object","properties":{"schema":{"$ref":"#/definitions/schema.VCJSONSchema"},"schemaJwt":{"type":"string"}}},"pkg_server_router.GetSubmissionResponse":{"type":"object","required":["status"],"properties":{"reason":{"description":"The reason why the submission was approved or denied.","type":"string"},"status":{"description":"One of {` + "`" + `pending` + "`" + `, ` + "`" + `approved` + "`" + `, ` + "`" + `denied` + "`" + `, ` + "`" + `cancelled` + "`" + `}.","type":"string"},"verifiablePresentation":{"description":"The verifiable presentation containing the presentation_submission along with the credentials presented.","allOf":[{"$ref":"#/definitions/credential.VerifiablePresentation"}]}}},"pkg_server_router.ListApplicationsResponse":{"type":"object","properties":{"applications":{"type":"array","items":{"$ref":"#/definitions/manifest.CredentialApplication"}}}},"pkg_server_router.ListCredentialsResponse":{"type":"object","properties":{"credentials":{"description":"Array of credential containers.","type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_internal_credential.Container"}}}},"pkg_server_router.ListDIDMethodsResponse":{"type":"object","properties":{"method":{"type":"array","items":{"$ref":"#/definitions/did.Method"}}}},"pkg_server_router.ListDIDsByMethodResponse":{"type":"object","properties":{"dids":{"type":"array","items":{"$ref":"#/definitions/did.Document"}}}},"pkg_server_router.ListDefinitionsResponse":{"type":"object","properties":{"definitions":{"type":"array","items":{"$ref":"#/definitions/exchange.PresentationDefinition"}}}},"pkg_server_router.ListIssuanceTemplatesResponse":{"type":"object","properties":{"issuanceTemplates":{"type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.Template"}}}},"pkg_server_router.ListManifestRequestsResponse":{"type":"object","properties":{"manifestRequests":{"description":"The manifest requests matching the query.","type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_manifest_model.Request"}}}},"pkg_server_router.ListManifestResponse":{"type":"object","properties":{"credential_manifest":{"$ref":"#/definitions/manifest.CredentialManifest"},"id":{"type":"string"}}},"pkg_server_router.ListManifestsResponse":{"type":"object","properties":{"manifests":{"type":"array","items":{"$ref":"#/definitions/pkg_server_router.ListManifestResponse"}}}},"pkg_server_router.ListOperationsResponse":{"type":"object","properties":{"operations":{"type":"array","items":{"$ref":"#/definitions/pkg_server_router.Operation"}}}},"pkg_server_router.ListResponsesResponse":{"type":"object","properties":{"responses":{"type":"array","items":{"$ref":"#/definitions/manifest.CredentialResponse"}}}},"pkg_server_router.ListSchemasResponse":{"type":"object","properties":{"schemas":{"type":"array","items":{"$ref":"#/definitions/pkg_server_router.GetSchemaResponse"}}}},"pkg_server_router.ListSubmissionResponse":{"type":"object","properties":{"submissions":{"type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission"}}}},"pkg_server_router.ListWebhookResponse":{"type":"object","properties":{"webhook":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Webhook"}}},"pkg_server_router.ListWebhooksResponse":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/definitions/pkg_server_router.ListWebhookResponse"}}}},"pkg_server_router.Operation":{"type":"object","required":["done","id"],"properties":{"done":{"description":"Whether this operation has finished.","type":"boolean"},"id":{"description":"The name of the resource related to this operation. E.g. \"presentations/submissions/\u003cuuid\u003e\"","type":"string"},"result":{"description":"Populated if Done == true.","allOf":[{"$ref":"#/definitions/pkg_server_router.OperationResult"}]}}},"pkg_server_router.OperationResult":{"type":"object","properties":{"error":{"description":"Populated when there was an error with the operation.","type":"string"},"response":{"description":"Populated iff Error == \"\". The type should be specified in the calling APIs documentation."}}},"pkg_server_router.ResolveDIDResponse":{"type":"object","properties":{"didDocument":{"$ref":"#/definitions/did.Document"},"didDocumentMetadata":{"$ref":"#/definitions/resolution.DocumentMetadata"},"didResolutionMetadata":{"$ref":"#/definitions/resolution.ResolutionMetadata"}}},"pkg_server_router.ReviewApplicationRequest":{"type":"object","properties":{"approved":{"type":"boolean"},"credentialOverrides":{"description":"Overrides to apply to the credentials that will be created. Keys are the ID that corresponds to an\nOutputDescriptor.ID from the manifest.","type":"object","additionalProperties":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_manifest_model.CredentialOverride"}},"reason":{"type":"string"}}},"pkg_server_router.ReviewSubmissionRequest":{"type":"object","required":["approved"],"properties":{"approved":{"type":"boolean"},"reason":{"type":"string"}}},"pkg_server_router.ReviewSubmissionResponse":{"type":"object","required":["status"],"properties":{"reason":{"description":"The reason why the submission was approved or denied.","type":"string"},"status":{"description":"One of {` + "`" + `pending` + "`" + `, ` + "`" + `approved` + "`" + `, ` + "`" + `denied` + "`" + `, ` + "`" + `cancelled` + "`" + `}.","type":"string"},"verifiablePresentation":{"description":"The verifiable presentation containing the presentation_submission along with the credentials presented.","allOf":[{"$ref":"#/definitions/credential.VerifiablePresentation"}]}}},"pkg_server_router.RevokeKeyResponse":{"type":"object","properties":{"id":{"type":"string"}}},"pkg_server_router.StoreKeyRequest":{"type":"object","required":["base58PrivateKey","controller","id","type"],"properties":{"base58PrivateKey":{"description":"Base58 encoding of the bytes that result from marshalling the private key using golang's implementation.","type":"string"},"controller":{"description":"See https://www.w3.org/TR/did-core/#did-controller","type":"string"},"id":{"description":"The ` + "`" + `id` + "`" + ` field is the unique identifier for this object. If set to a resolvable DID, the ssi-service will use\nthe private key encoded in the ` + "`" + `PrivateKeyBase58` + "`" + ` field of this object to sign objects issued or authored by this\nDID; otherwise, it will only be used to identify this object.","type":"string"},"type":{"description":"Identifies the cryptographic algorithm family used with the key.\nOne of the following: \"Ed25519\", \"X25519\", \"secp256k1\", \"P-224\", \"P-256\", \"P-384\", \"P-521\", \"RSA\".","allOf":[{"$ref":"#/definitions/crypto.KeyType"}]}}},"pkg_server_router.SubmitApplicationRequest":{"type":"object","required":["applicationJwt"],"properties":{"applicationJwt":{"description":"Contains the following properties:\nApplication manifestsdk.CredentialApplication ` + "`" + `json:\"credential_application\" validate:\"required\"` + "`" + `\nCredentials []interface{} ` + "`" + `json:\"vcs\" validate:\"required\"` + "`" + `","type":"string"}}},"pkg_server_router.SubmitApplicationResponse":{"type":"object","properties":{"credential_response":{"$ref":"#/definitions/manifest.CredentialResponse"},"responseJwt":{"type":"string"},"verifiableCredentials":{"description":"this is an any type to union Data Integrity and JWT style VCs","type":"array","items":{}}}},"pkg_server_router.UpdateCredentialStatusRequest":{"type":"object","properties":{"revoked":{"description":"The new revoked status of this credential. The status will be saved in the encodedList of the StatusList2021\ncredential associated with this VC.","type":"boolean"},"suspended":{"type":"boolean"}}},"pkg_server_router.UpdateCredentialStatusResponse":{"type":"object","properties":{"revoked":{"description":"The updated status of this credential.","type":"boolean"},"suspended":{"type":"boolean"}}},"pkg_server_router.VerifyCredentialRequest":{"type":"object","properties":{"credential":{"description":"A credential secured via data integrity. Must have the \"proof\" property set.","allOf":[{"$ref":"#/definitions/credential.VerifiableCredential"}]},"credentialJwt":{"description":"A JWT that encodes a credential.","type":"string"}}},"pkg_server_router.VerifyCredentialResponse":{"type":"object","properties":{"reason":{"description":"The reason why this credential couldn't be verified.","type":"string"},"verified":{"description":"Whether the credential was verified.","type":"boolean"}}},"pkg_server_router.VerifySchemaRequest":{"type":"object","required":["schemaJwt"],"properties":{"schemaJwt":{"type":"string"}}},"pkg_server_router.VerifySchemaResponse":{"type":"object","required":["verified"],"properties":{"reason":{"type":"string"},"verified":{"type":"boolean"}}},"rendering.ColorResource":{"type":"object","properties":{"color":{"description":"a HEX string color value (e.g. #00000)","type":"string"}}},"rendering.DataDisplay":{"type":"object","properties":{"description":{"$ref":"#/definitions/rendering.DisplayMappingObject"},"properties":{"type":"array","items":{"$ref":"#/definitions/rendering.LabeledDisplayMappingObject"}},"subtitle":{"$ref":"#/definitions/rendering.DisplayMappingObject"},"title":{"$ref":"#/definitions/rendering.DisplayMappingObject"}}},"rendering.DisplayMappingObject":{"type":"object","properties":{"fallback":{"type":"string"},"path":{"description":"Ifa path is present it must be an array of JSON Path string expressions\nand the schema property must also be present.","type":"array","items":{"type":"string"}},"schema":{"$ref":"#/definitions/rendering.DisplayMappingSchema"},"text":{"description":"If path is not present, the text value is required with no other properties","type":"string"}}},"rendering.DisplayMappingSchema":{"type":"object","required":["type"],"properties":{"format":{"description":"Must be present if the value of the type property is \"string\"","allOf":[{"$ref":"#/definitions/rendering.SchemaFormat"}]},"type":{"$ref":"#/definitions/rendering.SchemaType"}}},"rendering.EntityStyleDescriptor":{"type":"object","properties":{"background":{"$ref":"#/definitions/rendering.ColorResource"},"hero":{"$ref":"#/definitions/rendering.ImageResource"},"text":{"$ref":"#/definitions/rendering.ColorResource"},"thumbnail":{"$ref":"#/definitions/rendering.ImageResource"}}},"rendering.ImageResource":{"type":"object","required":["uri"],"properties":{"alt":{"description":"Describes the alternate text for a logo image","type":"string"},"uri":{"description":"Must be a valid URI string to an image resource","type":"string"}}},"rendering.LabeledDisplayMappingObject":{"type":"object","required":["label"],"properties":{"fallback":{"type":"string"},"label":{"type":"string"},"path":{"description":"Ifa path is present it must be an array of JSON Path string expressions\nand the schema property must also be present.","type":"array","items":{"type":"string"}},"schema":{"$ref":"#/definitions/rendering.DisplayMappingSchema"},"text":{"description":"If path is not present, the text value is required with no other properties","type":"string"}}},"rendering.SchemaFormat":{"type":"string","enum":["date-time","time","date","email","idn-email","hostname","idn-hostname","ipv4","ipv6","uri","uri-reference","iri","iri-reference"],"x-enum-varnames":["DateTimeFormat","TimeFormat","DateFormat","EmailFormat","IDNEmailFormat","HostnameFormat","IDNHostnameFormat","IPV4Format","IPV6Format","URIFormat","URIReferenceFormat","IRIFormat","IRIReferenceFormat"]},"rendering.SchemaType":{"type":"string","enum":["string","boolean","number","integer"],"x-enum-varnames":["StringType","BooleanType","NumberType","IntegerType"]},"resolution.DocumentMetadata":{"type":"object","properties":{"canonicalId":{"type":"string"},"created":{"type":"string"},"deactivated":{"type":"boolean"},"equivalentId":{"type":"string"},"nextUpdate":{"type":"string"},"nextVersionId":{"type":"string"},"updated":{"type":"string"},"versionId":{"type":"string"}}},"resolution.ResolutionError":{"type":"object","properties":{"code":{"type":"string"},"invalidDid":{"type":"boolean"},"notFound":{"type":"boolean"},"representationNotSupported":{"type":"boolean"}}},"resolution.ResolutionMetadata":{"type":"object","properties":{"contentType":{"type":"string"},"error":{"$ref":"#/definitions/resolution.ResolutionError"}}},"schema.JSONSchema":{"type":"object","additionalProperties":{}},"schema.VCJSONSchema":{"type":"object","properties":{"author":{"type":"string"},"authored":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"},"schema":{"$ref":"#/definitions/schema.JSONSchema"},"type":{"type":"string"},"version":{"type":"string"}}},"time.Duration":{"type":"integer","enum":[-9223372036854775808,9223372036854775807,1,1000,1000000,1000000000,60000000000,3600000000000],"x-enum-varnames":["minDuration","maxDuration","Nanosecond","Microsecond","Millisecond","Second","Minute","Hour"]}}}` + "schemes": {{ marshal .Schemes }},"swagger":"2.0","info":{"description":"{{escape .Description}}","title":"{{.Title}}","contact":{"name":"TBD","url":"https://github.com/TBD54566975/ssi-service/issues","email":"tbd-developer@squareup.com"},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"},"version":"{{.Version}}"},"host":"{{.Host}}","basePath":"{{.BasePath}}","paths":{"/health":{"get":{"description":"Health is a simple handler that always responds with a 200 OK","consumes":["application/json"],"produces":["application/json"],"tags":["HealthCheck"],"summary":"Health Check","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetHealthCheckResponse"}}}}},"/readiness":{"get":{"description":"Readiness runs a number of application specific checks to see if all the relied upon services are\nhealthy.","consumes":["application/json"],"produces":["application/json"],"tags":["Readiness"],"summary":"Readiness","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetReadinessResponse"}}}}},"/v1/credentials":{"get":{"description":"Checks for the presence of a query parameter and calls the associated filtered get method. Only one parameter is allowed to be specified.","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"List Credentials","parameters":[{"type":"string","example":"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp","description":"The issuer id","name":"issuer","in":"query"},{"type":"string","description":"The credentialSchema.id value to filter by","name":"schema","in":"query"},{"type":"string","description":"The credentialSubject.id value to filter by","name":"subject","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListCredentialsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create a verifiable credential","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Create Credential","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateCredentialRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateCredentialResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/credentials/status/{id}":{"get":{"description":"Get credential status list by id.","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Get Credential Status List","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetCredentialStatusListResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/credentials/verification":{"put":{"description":"Verify a given credential by its id. The system does the following levels of verification:\n1. Makes sure the credential has a valid signature\n2. Makes sure the credential has is not expired\n3. Makes sure the credential complies with the VC Data Model\n4. If the credential has a schema, makes sure its data complies with the schema","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Verify Credential","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.VerifyCredentialRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.VerifyCredentialResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/credentials/{id}":{"get":{"description":"Get credential by id","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Get Credential","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetCredentialResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"delete":{"description":"Delete credential by ID","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Delete Credentials","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/credentials/{id}/status":{"get":{"description":"Get credential status by id","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Get Credential Status","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetCredentialStatusResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Update a credential's status","consumes":["application/json"],"produces":["application/json"],"tags":["CredentialAPI"],"summary":"Update Credential Status","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.UpdateCredentialStatusRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.UpdateCredentialStatusResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/dids":{"get":{"description":"Get the list of supported DID methods","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"List DID Methods","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListDIDMethodsResponse"}}}}},"/v1/dids/resolver/{id}":{"get":{"description":"Resolve a DID that may not be stored in this service","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"Resolve a DID","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ResolveDIDResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}}},"/v1/dids/{method}":{"get":{"description":"List DIDs by method. Checks for an optional \"deleted=true\" query parameter, which exclusively returns DIDs that have been \"Soft Deleted\".","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"List DIDs","parameters":[{"type":"boolean","description":"When true, returns soft-deleted DIDs. Otherwise, returns DIDs that have not been soft-deleted. Default is false.","name":"deleted","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListDIDsByMethodResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Creates a fully custodial DID document with the given method. The document created is stored internally\nand can be retrieved using the GetOperation. Method dependent registration (for example, DID web\nregistration) is left up to the clients of this API. The private key(s) created by the method are stored\ninternally never leave the service boundary.","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"Create DID Document","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateDIDByMethodRequest"}},{"type":"string","description":"Method","name":"method","in":"path","required":true}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateDIDByMethodResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/dids/{method}/{id}":{"get":{"description":"Get DID by method","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"Get DID","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateDIDByMethodRequest"}},{"type":"string","description":"Method","name":"method","in":"path","required":true},{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetDIDByMethodResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"When this is called with the correct did method and id it will flip the softDelete flag to true for the db entry.\nA user can still get the did if they know the DID ID, and the did keys will still exist, but this did will not show up in the ListDIDsByMethod call\nThis facilitates a clean SSI-Service Admin UI but not leave any hanging VCs with inaccessible hanging DIDs.\nSoft Deletes DID by method","consumes":["application/json"],"produces":["application/json"],"tags":["DecentralizedIdentityAPI"],"summary":"Soft Delete DID","parameters":[{"type":"string","description":"Method","name":"method","in":"path","required":true},{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/issuancetemplates":{"put":{"description":"Create issuance template","consumes":["application/json"],"produces":["application/json"],"tags":["IssuanceAPI"],"summary":"Create issuance template","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateIssuanceTemplateRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.Template"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/issuancetemplates/{id}":{"get":{"description":"Get an issuance template by its id","consumes":["application/json"],"produces":["application/json"],"tags":["IssuanceAPI"],"summary":"Get issuance template","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.Template"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete issuance template by ID","consumes":["application/json"],"produces":["application/json"],"tags":["IssuanceAPI"],"summary":"Delete issuance template","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/keys":{"put":{"description":"Stores a key to be used by the service","consumes":["application/json"],"produces":["application/json"],"tags":["KeyStoreAPI"],"summary":"Store Key","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.StoreKeyRequest"}}],"responses":{"201":{"description":"Created"},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/keys/{id}":{"get":{"description":"Get details about a stored key","consumes":["application/json"],"produces":["application/json"],"tags":["KeyStoreAPI"],"summary":"Get Details For Key","parameters":[{"type":"string","description":"ID of the key to get","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetKeyDetailsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Marks the stored key as being revoked, along with the timestamps of when it was revoked. NB: the key can still be used for signing. This will likely be addressed before v1 is released.","consumes":["application/json"],"produces":["application/json"],"tags":["KeyStoreAPI"],"summary":"Revoke Key","parameters":[{"type":"string","description":"ID of the key to revoke","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.RevokeKeyResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests":{"get":{"description":"Checks for the presence of a query parameter and calls the associated filtered get method","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"List manifests","parameters":[{"type":"string","description":"string issuer","name":"issuer","in":"query"},{"type":"string","description":"string schema","name":"schema","in":"query"},{"type":"string","description":"string subject","name":"subject","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListManifestsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create manifest","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Create manifest","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateManifestRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateManifestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/applications":{"get":{"description":"List all the existing applications.","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"List applications","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListApplicationsResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Submit a credential application in response to a credential manifest. The request body is expected to","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"Submit application","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.SubmitApplicationRequest"}}],"responses":{"201":{"description":"Operation with a SubmitApplicationResponse type in the ` + "`" + `result.response` + "`" + ` field.","schema":{"$ref":"#/definitions/pkg_server_router.Operation"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/applications/{id}":{"get":{"description":"Get application by id","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"Get application","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetApplicationResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete application by ID","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"Delete applications","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/applications/{id}/review":{"put":{"description":"Reviewing an application either fulfills or denies the credential.","consumes":["application/json"],"produces":["application/json"],"tags":["ApplicationAPI"],"summary":"Reviews an application","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.ReviewApplicationRequest"}}],"responses":{"201":{"description":"Credential Response","schema":{"$ref":"#/definitions/pkg_server_router.SubmitApplicationResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/requests":{"get":{"description":"Lists all the existing credential manifest requests","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"List Credential Manifest Requests","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListManifestRequestsResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create manifest request from an existing credential manifest.","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Create Manifest Request Request","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateManifestRequestRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateManifestRequestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/requests/{id}":{"get":{"description":"Get a manifest request by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Get Manifest Request","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetManifestRequestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete a manifest request by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Delete Manifest Request","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/responses":{"get":{"description":"Lists all responses","consumes":["application/json"],"produces":["application/json"],"tags":["ResponseAPI"],"summary":"List responses","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListResponsesResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/responses/{id}":{"get":{"description":"Get response by id","consumes":["application/json"],"produces":["application/json"],"tags":["ResponseAPI"],"summary":"Get response","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetResponseResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"delete":{"description":"Delete response by ID","consumes":["application/json"],"produces":["application/json"],"tags":["ResponseAPI"],"summary":"Delete responses","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/manifests/{id}":{"get":{"description":"Get a credential manifest by its id","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Get manifest","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListManifestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete manifest by ID","consumes":["application/json"],"produces":["application/json"],"tags":["ManifestAPI"],"summary":"Delete manifests","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/operations":{"get":{"description":"List operations according to the request","consumes":["application/json"],"produces":["application/json"],"tags":["OperationAPI"],"summary":"List operations","parameters":[{"type":"string","description":"The name of the parent's resource. For example: ` + "`" + `?parent=/presentation/submissions` + "`" + `","name":"parent","in":"query"},{"type":"string","description":"A standard filter expression conforming to https://google.aip.dev/160. For example: ` + "`" + `?filter=done=","name":"filter","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListOperationsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/operations/cancel/{id}":{"get":{"description":"Cancels an ongoing operation, if possible.","consumes":["application/json"],"produces":["application/json"],"tags":["OperationAPI"],"summary":"Cancel an ongoing operation","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"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"}}}}},"/v1/operations/{id}":{"get":{"description":"Get operation by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["OperationAPI"],"summary":"Get an operation","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"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"}}}}},"/v1/presentations/definitions":{"get":{"description":"Lists all the existing presentation definitions","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationDefinitionAPI"],"summary":"List Presentation Definitions","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListDefinitionsResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create presentation definition","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationDefinitionAPI"],"summary":"Create PresentationDefinition","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreatePresentationDefinitionRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreatePresentationDefinitionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/definitions/{id}":{"get":{"description":"Get a presentation definition by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationDefinitionAPI"],"summary":"Get PresentationDefinition","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetPresentationDefinitionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete a presentation definition by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationDefinitionAPI"],"summary":"Delete PresentationDefinition","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/requests":{"put":{"description":"Create presentation request from an existing presentation definition.","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationRequestAPI"],"summary":"Create Presentation Request","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateRequestRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateRequestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/requests/{id}":{"get":{"description":"Get a presentation request by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationRequestAPI"],"summary":"Get Presentation Request","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetRequestResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete a presentation request by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationRequestAPI"],"summary":"Delete PresentationRequest","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/submissions":{"get":{"description":"List existing submissions according to a filtering query. The ` + "`" + `filter` + "`" + ` field follows the syntax described in https://google.aip.dev/160.","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationSubmissionAPI"],"summary":"List Submissions","parameters":[{"type":"string","description":"A standard filter expression conforming to https://google.aip.dev/160. For example: ` + "`" + `?filter=status=","name":"filter","in":"query"}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListSubmissionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Creates a submission in this server ready to be reviewed.","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationSubmissionAPI"],"summary":"Create Submission","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateSubmissionRequest"}}],"responses":{"201":{"description":"The type of response is Submission once the operation has finished.","schema":{"$ref":"#/definitions/pkg_server_router.Operation"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/presentations/submissions/{id}":{"get":{"description":"Get a submission by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationSubmissionAPI"],"summary":"Get Submission","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetSubmissionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}}},"/v1/presentations/submissions/{id}/review":{"put":{"description":"Reviews a pending submission. After this method is called, the operation with ` + "`" + `id==presentations/submissions/{submission_id}` + "`" + ` will be updated with the result of this invocation.","consumes":["application/json"],"produces":["application/json"],"tags":["PresentationSubmissionAPI"],"summary":"Review a pending submission","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.ReviewSubmissionRequest"}}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ReviewSubmissionResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/schemas":{"get":{"description":"List schemas","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"List Schemas","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListSchemasResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create schema","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"Create Schema","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateSchemaRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateSchemaResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/schemas/{id}":{"get":{"description":"Get a schema by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"Get Schema","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.GetSchemaResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}},"delete":{"description":"Delete a schema by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["SchemaAPI"],"summary":"Delete Schema","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/webhooks":{"get":{"description":"Lists all webhooks","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"List Webhooks","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListWebhooksResponse"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}},"put":{"description":"Create webhook","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Create Webhook","parameters":[{"description":"request body","name":"request","in":"body","required":true,"schema":{"$ref":"#/definitions/pkg_server_router.CreateWebhookRequest"}}],"responses":{"201":{"description":"Created","schema":{"$ref":"#/definitions/pkg_server_router.CreateWebhookResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}},"/v1/webhooks/nouns":{"get":{"description":"Get supported nouns for webhook generation","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Get Supported Nouns","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.GetSupportedNounsResponse"}}}}},"/v1/webhooks/verbs":{"get":{"description":"Get supported verbs for webhook generation","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Get Supported Verbs","responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.GetSupportedVerbsResponse"}}}}},"/v1/webhooks/{noun}/{verb}":{"get":{"description":"Get a webhook by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Get Webhook","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"200":{"description":"OK","schema":{"$ref":"#/definitions/pkg_server_router.ListWebhookResponse"}},"400":{"description":"Bad request","schema":{"type":"string"}}}}},"/v1/webhooks/{noun}/{verb}/{url}":{"delete":{"description":"Delete a webhook by its ID","consumes":["application/json"],"produces":["application/json"],"tags":["WebhookAPI"],"summary":"Delete Webhook","parameters":[{"type":"string","description":"ID","name":"id","in":"path","required":true}],"responses":{"204":{"description":"No Content","schema":{"type":"string"}},"400":{"description":"Bad request","schema":{"type":"string"}},"500":{"description":"Internal server error","schema":{"type":"string"}}}}}},"definitions":{"credential.CredentialSchema":{"type":"object","required":["id","type"],"properties":{"id":{"type":"string"},"type":{"type":"string"}}},"credential.CredentialSubject":{"type":"object","additionalProperties":{}},"credential.Prohibition":{"type":"object","properties":{"action":{"type":"array","items":{"type":"string"}},"assignee":{"type":"string"},"assigner":{"type":"string"},"target":{"type":"string"}}},"credential.RefreshService":{"type":"object","required":["id","type"],"properties":{"id":{"type":"string"},"type":{"type":"string"}}},"credential.TermsOfUse":{"type":"object","properties":{"id":{"type":"string"},"profile":{"type":"string"},"prohibition":{"type":"array","items":{"$ref":"#/definitions/credential.Prohibition"}},"type":{"type":"string"}}},"credential.VerifiableCredential":{"type":"object","required":["@context","credentialSubject","issuanceDate","issuer","type"],"properties":{"@context":{"description":"Either a string or set of strings"},"credentialSchema":{"$ref":"#/definitions/credential.CredentialSchema"},"credentialStatus":{},"credentialSubject":{"description":"This is where the subject's ID *may* be present","allOf":[{"$ref":"#/definitions/credential.CredentialSubject"}]},"evidence":{"type":"array","items":{}},"expirationDate":{"type":"string"},"id":{"type":"string"},"issuanceDate":{"description":"https://www.w3.org/TR/xmlschema11-2/#dateTimes","type":"string"},"issuer":{"description":"either a URI or an object containing an ` + "`" + `id` + "`" + ` property."},"proof":{"description":"For embedded proof support\nProof is a digital signature over a credential https://www.w3.org/TR/2021/REC-vc-data-model-20211109/#proofs-signatures"},"refreshService":{"$ref":"#/definitions/credential.RefreshService"},"termsOfUse":{"type":"array","items":{"$ref":"#/definitions/credential.TermsOfUse"}},"type":{"description":"Either a string or a set of strings https://www.w3.org/TR/2021/REC-vc-data-model-20211109/#types"}}},"credential.VerifiablePresentation":{"type":"object","required":["type"],"properties":{"@context":{"description":"Either a string or set of strings"},"holder":{"type":"string"},"id":{"type":"string"},"presentation_submission":{"description":"an optional field as a part of https://identity.foundation/presentation-exchange/#embed-targets"},"proof":{},"type":{},"verifiableCredential":{"description":"Verifiable credential could be our object model, a JWT, or any other valid credential representation","type":"array","items":{}}}},"crypto.KeyType":{"type":"string","enum":["Ed25519","X25519","secp256k1","secp256k1-ECDSA","P-224","P-256","P-384","P-521","RSA","BLS12381G1","BLS12381G2","Dilithium2","Dilithium3","Dilithium5"],"x-enum-varnames":["Ed25519","X25519","SECP256k1","SECP256k1ECDSA","P224","P256","P384","P521","RSA","BLS12381G1","BLS12381G2","Dilithium2","Dilithium3","Dilithium5"]},"crypto.SignatureAlgorithm":{"type":"string","enum":["EdDSA","ES256K","ES256","ES384","PS256","Dilithium2","Dilithium3","Dilithium5"],"x-enum-varnames":["EdDSA","ES256K","ES256","ES384","PS256","Dilithium2Sig","Dilithium3Sig","Dilithium5Sig"]},"did.Document":{"type":"object","properties":{"@context":{},"alsoKnownAs":{"type":"string"},"assertionMethod":{"type":"array","items":{}},"authentication":{"type":"array","items":{}},"capabilityDelegation":{"type":"array","items":{}},"capabilityInvocation":{"type":"array","items":{}},"controller":{"type":"string"},"id":{"description":"As per https://www.w3.org/TR/did-core/#did-subject intermediate representations of DID Documents do not\nrequire an ID property. The provided test vectors demonstrate IRs. As such, the property is optional.","type":"string"},"keyAgreement":{"type":"array","items":{}},"service":{"type":"array","items":{"$ref":"#/definitions/github_com_TBD54566975_ssi-sdk_did.Service"}},"verificationMethod":{"type":"array","items":{"$ref":"#/definitions/did.VerificationMethod"}}}},"did.Method":{"type":"string","enum":["key","peer","pkh","web","ion","jwk"],"x-enum-varnames":["KeyMethod","PeerMethod","PKHMethod","WebMethod","IONMethod","JWKMethod"]},"did.VerificationMethod":{"type":"object","required":["controller","id","type"],"properties":{"blockchainAccountId":{"description":"for PKH DIDs - https://github.com/w3c-ccg/did-pkh/blob/90b28ad3c18d63822a8aab3c752302aa64fc9382/did-pkh-method-draft.md","type":"string"},"controller":{"type":"string"},"id":{"type":"string"},"publicKeyBase58":{"type":"string"},"publicKeyJwk":{"description":"must conform to https://datatracker.ietf.org/doc/html/rfc7517","allOf":[{"$ref":"#/definitions/jwx.PublicKeyJWK"}]},"publicKeyMultibase":{"description":"https://datatracker.ietf.org/doc/html/draft-multiformats-multibase-03","type":"string"},"type":{"type":"string"}}},"exchange.ClaimFormat":{"type":"object","properties":{"jwt":{"$ref":"#/definitions/exchange.JWTType"},"jwt_vc":{"$ref":"#/definitions/exchange.JWTType"},"jwt_vp":{"$ref":"#/definitions/exchange.JWTType"},"ldp":{"$ref":"#/definitions/exchange.LDPType"},"ldp_vc":{"$ref":"#/definitions/exchange.LDPType"},"ldp_vp":{"$ref":"#/definitions/exchange.LDPType"}}},"exchange.Constraints":{"type":"object","properties":{"fields":{"type":"array","items":{"$ref":"#/definitions/exchange.Field"}},"is_holder":{"type":"array","items":{"$ref":"#/definitions/exchange.RelationalConstraint"}},"limit_disclosure":{"$ref":"#/definitions/exchange.Preference"},"same_subject":{"type":"array","items":{"$ref":"#/definitions/exchange.RelationalConstraint"}},"statuses":{"description":"https://identity.foundation/presentation-exchange/#credential-status-constraint-feature","allOf":[{"$ref":"#/definitions/exchange.CredentialStatus"}]},"subject_is_issuer":{"description":"https://identity.foundation/presentation-exchange/#relational-constraint-feature","allOf":[{"$ref":"#/definitions/exchange.Preference"}]}}},"exchange.CredentialStatus":{"type":"object","properties":{"active":{"type":"object","properties":{"directive":{"$ref":"#/definitions/exchange.Preference"}}},"revoked":{"type":"object","properties":{"directive":{"$ref":"#/definitions/exchange.Preference"}}},"suspended":{"type":"object","properties":{"directive":{"$ref":"#/definitions/exchange.Preference"}}}}},"exchange.Field":{"type":"object","required":["path"],"properties":{"filter":{"$ref":"#/definitions/exchange.Filter"},"id":{"type":"string"},"intent_to_retain":{"description":"https://identity.foundation/presentation-exchange/spec/v2.0.0/#retention-feature","type":"boolean"},"name":{"type":"string"},"optional":{"type":"boolean"},"path":{"type":"array","items":{"type":"string"}},"predicate":{"description":"If a predicate property is present, filter must be too\nhttps://identity.foundation/presentation-exchange/#predicate-feature","allOf":[{"$ref":"#/definitions/exchange.Preference"}]},"purpose":{"type":"string"}}},"exchange.Filter":{"type":"object","properties":{"additionalProperties":{"type":"boolean"},"allOf":{},"const":{},"enum":{"type":"array","items":{}},"exclusiveMaximum":{},"exclusiveMinimum":{},"format":{"type":"string"},"maxLength":{"type":"integer"},"maximum":{},"minLength":{"type":"integer"},"minimum":{},"not":{},"oneOf":{},"pattern":{"type":"string"},"properties":{},"required":{"type":"array","items":{"type":"string"}},"type":{"type":"string"}}},"exchange.InputDescriptor":{"type":"object","required":["constraints","id"],"properties":{"constraints":{"$ref":"#/definitions/exchange.Constraints"},"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"group":{"description":"Must match a grouping strings listed in the ` + "`" + `from` + "`" + ` values of a submission requirement rule","type":"array","items":{"type":"string"}},"id":{"description":"Must be unique within the Presentation Definition","type":"string"},"name":{"type":"string"},"purpose":{"description":"Purpose for which claim's data is being requested","type":"string"}}},"exchange.JWTType":{"type":"object","required":["alg"],"properties":{"alg":{"type":"array","items":{"$ref":"#/definitions/crypto.SignatureAlgorithm"}}}},"exchange.LDPType":{"type":"object","required":["proof_type"],"properties":{"proof_type":{"type":"array","items":{"type":"string"}}}},"exchange.Preference":{"type":"string","enum":["required","preferred","allowed","disallowed"],"x-enum-varnames":["Required","Preferred","Allowed","Disallowed"]},"exchange.PresentationDefinition":{"type":"object","required":["id","input_descriptors"],"properties":{"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"frame":{"description":"https://identity.foundation/presentation-exchange/#json-ld-framing-feature"},"id":{"type":"string"},"input_descriptors":{"type":"array","items":{"$ref":"#/definitions/exchange.InputDescriptor"}},"name":{"type":"string"},"purpose":{"type":"string"},"submission_requirements":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionRequirement"}}}},"exchange.PresentationSubmission":{"type":"object","required":["definition_id","descriptor_map","id"],"properties":{"definition_id":{"type":"string"},"descriptor_map":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionDescriptor"}},"id":{"type":"string"}}},"exchange.RelationalConstraint":{"type":"object","required":["directive","field_id"],"properties":{"directive":{"$ref":"#/definitions/exchange.Preference"},"field_id":{"type":"array","items":{"type":"string"}}}},"exchange.Selection":{"type":"string","enum":["all","pick"],"x-enum-varnames":["All","Pick"]},"exchange.SubmissionDescriptor":{"type":"object","required":["format","id","path"],"properties":{"format":{"type":"string"},"id":{"description":"Must match the ` + "`" + `id` + "`" + ` property of the corresponding input descriptor","type":"string"},"path":{"type":"string"},"path_nested":{"$ref":"#/definitions/exchange.SubmissionDescriptor"}}},"exchange.SubmissionRequirement":{"type":"object","required":["rule"],"properties":{"count":{"type":"integer","minimum":1},"from":{"type":"string"},"from_nested":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionRequirement"}},"max":{"type":"integer"},"min":{"type":"integer"},"name":{"type":"string"},"purpose":{"type":"string"},"rule":{"$ref":"#/definitions/exchange.Selection"}}},"github_com_TBD54566975_ssi-sdk_did.Service":{"type":"object","required":["id","serviceEndpoint","type"],"properties":{"accept":{"type":"array","items":{"type":"string"}},"id":{"type":"string"},"routingKeys":{"type":"array","items":{"type":"string"}},"serviceEndpoint":{"description":"A string, map, or set composed of one or more strings and/or maps\nAll string values must be valid URIs"},"type":{"type":"string"}}},"github_com_tbd54566975_ssi-service_internal_credential.Container":{"type":"object","properties":{"credential":{"$ref":"#/definitions/credential.VerifiableCredential"},"credentialJwt":{"type":"string"},"id":{"description":"Credential ID","type":"string"},"issuerKid":{"type":"string"},"revoked":{"type":"boolean"},"suspended":{"type":"boolean"}}},"github_com_tbd54566975_ssi-service_pkg_service_framework.Status":{"type":"object","properties":{"message":{"description":"When ` + "`" + `status` + "`" + ` is ` + "`" + `not_ready` + "`" + `, then message contains explanation of why it's not ready.","type":"string"},"status":{"description":"Either ` + "`" + `ready` + "`" + ` or ` + "`" + `not_ready` + "`" + `.","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_framework.StatusState"}]}}},"github_com_tbd54566975_ssi-service_pkg_service_framework.StatusState":{"type":"string","enum":["ready","not_ready"],"x-enum-varnames":["StatusReady","StatusNotReady"]},"github_com_tbd54566975_ssi-service_pkg_service_issuance.ClaimTemplates":{"type":"object","additionalProperties":{}},"github_com_tbd54566975_ssi-service_pkg_service_issuance.CredentialTemplate":{"type":"object","properties":{"credentialInputDescriptor":{"description":"Optional.\nWhen present, it's the ID of the input descriptor in the application. Corresponds to one of the\nPresentationDefinition.InputDescriptors[].ID in the credential manifest. When creating a credential, the base\ndata will be populated from the provided submission that matches this ID.\nWhen absent, there will be no base data for the credentials created. Additionally, no JSON path strings in\nClaimTemplates.Data will be resolved.","type":"string"},"data":{"description":"Data that will be used to determine credential claims.\nValues may be json path like strings, or any other JSON primitive. Each entry will be used to come up with a\nclaim about the credentialSubject in the credential that will be issued.","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.ClaimTemplates"}]},"expiry":{"description":"Parameter to determine the expiry of the credential.","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.TimeLike"}]},"id":{"description":"ID corresponding to an OutputDescriptor.ID from the manifest.","type":"string"},"revocable":{"description":"Whether the credentials created should be revocable.","type":"boolean"},"schema":{"description":"ID of the CredentialSchema to be used for the issued credential.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_issuance.Template":{"type":"object","required":["credentialManifest","issuer","issuerKid"],"properties":{"credentialManifest":{"description":"ID of the credential manifest that this template corresponds to.","type":"string"},"credentials":{"description":"Info required to create a credential from a credential application.","type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.CredentialTemplate"}},"id":{"description":"ID of this template.","type":"string"},"issuer":{"description":"ID of the issuer that will be issuance the credentials.","type":"string"},"issuerKid":{"description":"ID of the key that will be used to sign the credentials.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_issuance.TimeLike":{"type":"object","properties":{"duration":{"description":"For a fixed offset from when it was issued.","allOf":[{"$ref":"#/definitions/time.Duration"}]},"time":{"description":"For fixed time in the future.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_manifest_model.CredentialOverride":{"type":"object","properties":{"data":{"description":"Data that will be used to determine credential claims.","type":"object","additionalProperties":{}},"expiry":{"description":"Parameter to determine the expiry of the credential.","type":"string"},"revocable":{"description":"Whether the credentials created should be revocable.","type":"boolean"}}},"github_com_tbd54566975_ssi-service_pkg_service_manifest_model.Request":{"type":"object","required":["expiration","issuerId","issuerKid","manifestId"],"properties":{"audience":{"description":"Audience as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3.","type":"array","items":{"type":"string"}},"credentialManifestJwt":{"description":"CredentialManifestJWT is a JWT token with a \"presentation_definition\" claim within it. The\nvalue of the field named \"presentation_definition.id\" matches PresentationDefinitionID.\nThis is an output only field.","type":"string"},"expiration":{"description":"Expiration as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4","type":"string"},"id":{"description":"ID for this request. It matches the \"jti\" claim in the JWT.\nThis is an output only field.","type":"string"},"issuerId":{"description":"DID of the issuer of this presentation definition.","type":"string"},"issuerKid":{"description":"The privateKey associated with the KID used to sign the JWT.","type":"string"},"manifestId":{"description":"ID of the credential manifest used for this request.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Request":{"type":"object","required":["expiration","issuerId","issuerKid","presentationDefinitionId"],"properties":{"audience":{"description":"Audience as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3.","type":"array","items":{"type":"string"}},"expiration":{"description":"Expiration as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4","type":"string"},"id":{"description":"ID for this request. It matches the \"jti\" claim in the JWT.\nThis is an output only field.","type":"string"},"issuerId":{"description":"DID of the issuer of this presentation definition.","type":"string"},"issuerKid":{"description":"The privateKey associated with the KID used to sign the JWT.","type":"string"},"presentationDefinitionId":{"description":"ID of the presentation definition used for this request.","type":"string"},"presentationRequestJwt":{"description":"PresentationDefinitionJWT is a JWT token with a \"presentation_definition\" claim within it. The\nvalue of the field named \"presentation_definition.id\" matches PresentationDefinitionID.\nThis is an output only field.","type":"string"}}},"github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission":{"type":"object","required":["status"],"properties":{"reason":{"description":"The reason why the submission was approved or denied.","type":"string"},"status":{"description":"One of {` + "`" + `pending` + "`" + `, ` + "`" + `approved` + "`" + `, ` + "`" + `denied` + "`" + `, ` + "`" + `cancelled` + "`" + `}.","type":"string"},"verifiablePresentation":{"description":"The verifiable presentation containing the presentation_submission along with the credentials presented.","allOf":[{"$ref":"#/definitions/credential.VerifiablePresentation"}]}}},"github_com_tbd54566975_ssi-service_pkg_service_webhook.GetSupportedNounsResponse":{"type":"object","properties":{"nouns":{"type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Noun"}}}},"github_com_tbd54566975_ssi-service_pkg_service_webhook.GetSupportedVerbsResponse":{"type":"object","properties":{"verbs":{"type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Verb"}}}},"github_com_tbd54566975_ssi-service_pkg_service_webhook.Noun":{"type":"string","enum":["Credential","DID","Manifest","SchemaID","Presentation","Application","Submission"],"x-enum-varnames":["Credential","DID","Manifest","Schema","Presentation","Application","Submission"]},"github_com_tbd54566975_ssi-service_pkg_service_webhook.Verb":{"type":"string","enum":["Create","Delete"],"x-enum-varnames":["Create","Delete"]},"github_com_tbd54566975_ssi-service_pkg_service_webhook.Webhook":{"type":"object","required":["noun","urls","verb"],"properties":{"noun":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Noun"},"urls":{"type":"array","items":{"type":"string"}},"verb":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Verb"}}},"jwx.PublicKeyJWK":{"type":"object","required":["kty"],"properties":{"alg":{"type":"string"},"crv":{"type":"string"},"e":{"type":"string"},"key_ops":{"type":"string"},"kid":{"type":"string"},"kty":{"type":"string"},"n":{"type":"string"},"use":{"type":"string"},"x":{"type":"string"},"y":{"type":"string"}}},"manifest.CredentialApplication":{"type":"object","required":["format","id","manifest_id","spec_version"],"properties":{"applicant":{"type":"string"},"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"id":{"type":"string"},"manifest_id":{"type":"string"},"presentation_submission":{"description":"Must be present if the corresponding manifest contains a presentation_definition","allOf":[{"$ref":"#/definitions/exchange.PresentationSubmission"}]},"spec_version":{"type":"string"}}},"manifest.CredentialManifest":{"type":"object","required":["id","issuer","output_descriptors","spec_version"],"properties":{"description":{"type":"string"},"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"id":{"type":"string"},"issuer":{"$ref":"#/definitions/manifest.Issuer"},"name":{"type":"string"},"output_descriptors":{"type":"array","items":{"$ref":"#/definitions/manifest.OutputDescriptor"}},"presentation_definition":{"$ref":"#/definitions/exchange.PresentationDefinition"},"spec_version":{"type":"string"}}},"manifest.CredentialResponse":{"type":"object","required":["id","manifest_id","spec_version"],"properties":{"applicant":{"type":"string"},"application_id":{"type":"string"},"denial":{"type":"object","required":["reason"],"properties":{"input_descriptors":{"type":"array","items":{"type":"string"}},"reason":{"type":"string"}}},"fulfillment":{"type":"object","required":["descriptor_map"],"properties":{"descriptor_map":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionDescriptor"}}}},"id":{"type":"string"},"manifest_id":{"type":"string"},"spec_version":{"type":"string"}}},"manifest.Issuer":{"type":"object","required":["id"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"styles":{"description":"an object or URI as defined by the DIF Entity Styles specification\nhttps://identity.foundation/wallet-rendering/#entity-styles","allOf":[{"$ref":"#/definitions/rendering.EntityStyleDescriptor"}]}}},"manifest.OutputDescriptor":{"type":"object","required":["id","schema"],"properties":{"description":{"type":"string"},"display":{"description":"both below: an object or URI as defined by the DIF Entity Styles specification","allOf":[{"$ref":"#/definitions/rendering.DataDisplay"}]},"id":{"description":"Must be unique within a manifest","type":"string"},"name":{"type":"string"},"schema":{"type":"string"},"styles":{"$ref":"#/definitions/rendering.EntityStyleDescriptor"}}},"pkg_server_router.CreateCredentialRequest":{"type":"object","required":["data","issuer","issuerKid","subject"],"properties":{"@context":{"description":"A context is optional. If not present, we'll apply default, required context values.","type":"string"},"data":{"description":"Claims about the subject. The keys should be predicates (e.g. \"alumniOf\"), and the values can be any object.","type":"object","additionalProperties":{"type":"string"},"example":{"alumniOf":"did_for_uni"}},"expiry":{"description":"Optional. Corresponds to ` + "`" + `expirationDate` + "`" + ` in https://www.w3.org/TR/vc-data-model/#expiration.","type":"string","example":"2020-01-01T19:23:24Z"},"issuer":{"description":"The issuer id.","type":"string","example":"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"},"issuerKid":{"description":"The KID used to sign the credential","type":"string","example":"#z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"},"revocable":{"description":"Whether this credential can be revoked. When true, the created VC will have the \"credentialStatus\"\nproperty set.","type":"boolean"},"schemaId":{"description":"A schema ID is optional. If present, we'll attempt to look it up and validate the data against it.","type":"string"},"subject":{"description":"The subject id.","type":"string","example":"did:key:z6MkiTBz1ymuepAQ4HEHYSF1H8quG5GLVVQR3djdX3mDooWp"},"suspendable":{"description":"Whether this credential can be suspended. When true, the created VC will have the \"credentialStatus\"\nproperty set.","type":"boolean"}}},"pkg_server_router.CreateCredentialResponse":{"type":"object","properties":{"credential":{"description":"A verifiable credential conformant to the media type ` + "`" + `application/vc+ld+json` + "`" + `.","allOf":[{"$ref":"#/definitions/credential.VerifiableCredential"}]},"credentialJwt":{"description":"The same verifiable credential, but using the syntax defined for the media type ` + "`" + `application/vc+jwt` + "`" + `. See\nhttps://w3c.github.io/vc-jwt/ for more details.","type":"string"}}},"pkg_server_router.CreateDIDByMethodRequest":{"type":"object","required":["keyType"],"properties":{"keyType":{"description":"Identifies the cryptographic algorithm family to use when generating this key.\nOne of the following: \"Ed25519\", \"X25519\", \"secp256k1\", \"P-224\",\"P-256\",\"P-384\", \"P-521\", \"RSA\"","allOf":[{"$ref":"#/definitions/crypto.KeyType"}]},"options":{"description":"Options for creating the DID. Implementation dependent on the method."}}},"pkg_server_router.CreateDIDByMethodResponse":{"type":"object","properties":{"did":{"$ref":"#/definitions/did.Document"}}},"pkg_server_router.CreateIssuanceTemplateRequest":{"type":"object","required":["credentialManifest","issuer","issuerKid"],"properties":{"credentialManifest":{"description":"ID of the credential manifest that this template corresponds to.","type":"string"},"credentials":{"description":"Info required to create a credential from a credential application.","type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.CredentialTemplate"}},"id":{"description":"ID of this template.","type":"string"},"issuer":{"description":"ID of the issuer that will be issuance the credentials.","type":"string"},"issuerKid":{"description":"ID of the key that will be used to sign the credentials.","type":"string"}}},"pkg_server_router.CreateManifestRequest":{"type":"object","required":["format","issuerDid","issuerKid","outputDescriptors"],"properties":{"description":{"type":"string"},"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"issuerDid":{"type":"string"},"issuerKid":{"type":"string"},"issuerName":{"type":"string"},"name":{"type":"string"},"outputDescriptors":{"type":"array","items":{"$ref":"#/definitions/manifest.OutputDescriptor"}},"presentationDefinition":{"$ref":"#/definitions/exchange.PresentationDefinition"}}},"pkg_server_router.CreateManifestRequestRequest":{"type":"object","required":["credentialManifestId","issuerId","issuerKid"],"properties":{"audience":{"description":"Audience as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3\nOptional","type":"array","items":{"type":"string"}},"credentialManifestId":{"description":"ID of the credential manifest to use for this request.","type":"string"},"expiration":{"description":"Expiration as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4\nOptional. When not specified, the request will be valid for a default duration.","type":"string"},"issuerId":{"description":"DID of the issuer of this presentation definition. The DID must have been previously created with the DID API,\nor the PrivateKey must have been added independently.","type":"string"},"issuerKid":{"description":"The privateKey associated with the KID will be used to sign an envelope that contains\nthe created presentation definition.","type":"string"}}},"pkg_server_router.CreateManifestRequestResponse":{"type":"object","properties":{"manifestRequest":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_manifest_model.Request"}}},"pkg_server_router.CreateManifestResponse":{"type":"object","properties":{"credential_manifest":{"$ref":"#/definitions/manifest.CredentialManifest"}}},"pkg_server_router.CreatePresentationDefinitionRequest":{"type":"object","required":["inputDescriptors"],"properties":{"format":{"$ref":"#/definitions/exchange.ClaimFormat"},"inputDescriptors":{"type":"array","items":{"$ref":"#/definitions/exchange.InputDescriptor"}},"name":{"type":"string"},"purpose":{"type":"string"},"submissionRequirements":{"type":"array","items":{"$ref":"#/definitions/exchange.SubmissionRequirement"}}}},"pkg_server_router.CreatePresentationDefinitionResponse":{"type":"object","properties":{"presentationDefinitionJwt":{"description":"Signed envelope that contains the PresentationDefinition created using the privateKey of the author of the\ndefinition.","type":"string"},"presentation_definition":{"$ref":"#/definitions/exchange.PresentationDefinition"}}},"pkg_server_router.CreateRequestRequest":{"type":"object","required":["issuerId","issuerKid","presentationDefinitionId"],"properties":{"audience":{"description":"Audience as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.3\nOptional","type":"array","items":{"type":"string"}},"expiration":{"description":"Expiration as defined in https://www.rfc-editor.org/rfc/rfc7519.html#section-4.1.4\nOptional. When not specified, the request will be valid for a default duration.","type":"string"},"issuerId":{"description":"DID of the issuer of this presentation definition. The DID must have been previously created with the DID API,\nor the PrivateKey must have been added independently.","type":"string"},"issuerKid":{"description":"The privateKey associated with the KID will be used to sign an envelope that contains\nthe created presentation definition.","type":"string"},"presentationDefinitionId":{"description":"ID of the presentation definition to use for this request.","type":"string"}}},"pkg_server_router.CreateRequestResponse":{"type":"object","properties":{"presentationRequest":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Request"}}},"pkg_server_router.CreateSchemaRequest":{"type":"object","required":["name","schema"],"properties":{"description":{"description":"Description is an optional human-readable description for a schema","type":"string"},"name":{"description":"Name is a human-readable name for a schema","type":"string"},"schema":{"description":"Schema represents the JSON schema for the credential schema\nIf the schema has an $id field, it will be overwritten with an ID the service generates.\nThe schema must be against draft 2020-12, 2019-09, or 7.","allOf":[{"$ref":"#/definitions/schema.JSONSchema"}]}}},"pkg_server_router.CreateSchemaResponse":{"type":"object","properties":{"credentialSchema":{"type":"string"},"id":{"type":"string"},"schema":{"$ref":"#/definitions/schema.JSONSchema"}}},"pkg_server_router.CreateSubmissionRequest":{"type":"object","required":["submissionJwt"],"properties":{"submissionJwt":{"description":"A Verifiable Presentation that's encoded as a JWT.\nVerifiable Presentation are described in https://www.w3.org/TR/vc-data-model/#presentations-0\nJWT encoding of the Presentation as described in https://www.w3.org/TR/vc-data-model/#presentations-0","type":"string"}}},"pkg_server_router.CreateWebhookRequest":{"type":"object","required":["noun","url","verb"],"properties":{"noun":{"description":"The noun (entity) for the new webhook.eg: Credential","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Noun"}]},"url":{"description":"The URL to post the output of this request to Noun.Verb action to.","type":"string"},"verb":{"description":"The verb for the new webhook.eg: Create","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Verb"}]}}},"pkg_server_router.CreateWebhookResponse":{"type":"object","properties":{"webhook":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Webhook"}}},"pkg_server_router.GetApplicationResponse":{"type":"object","properties":{"application":{"$ref":"#/definitions/manifest.CredentialApplication"},"id":{"type":"string"}}},"pkg_server_router.GetCredentialResponse":{"type":"object","properties":{"credential":{"$ref":"#/definitions/credential.VerifiableCredential"},"credentialJwt":{"type":"string"},"id":{"type":"string"}}},"pkg_server_router.GetCredentialStatusListResponse":{"type":"object","properties":{"credential":{"description":"Credential where type includes \"VerifiableCredential\" and \"StatusList2021\".","allOf":[{"$ref":"#/definitions/credential.VerifiableCredential"}]},"credentialJwt":{"description":"The JWT signed with the associated issuer's private key.","type":"string"},"id":{"type":"string"}}},"pkg_server_router.GetCredentialStatusResponse":{"type":"object","properties":{"revoked":{"description":"Whether the credential has been revoked.","type":"boolean"},"suspended":{"description":"Whether the credential has been suspended.","type":"boolean"}}},"pkg_server_router.GetDIDByMethodResponse":{"type":"object","properties":{"did":{"$ref":"#/definitions/did.Document"}}},"pkg_server_router.GetHealthCheckResponse":{"type":"object","properties":{"status":{"description":"Status is always equal to ` + "`" + `OK` + "`" + `.","type":"string"}}},"pkg_server_router.GetKeyDetailsResponse":{"type":"object","properties":{"controller":{"type":"string"},"createdAt":{"description":"Represents the time at which the key was created. Encoded according to RFC3339.","type":"string"},"id":{"type":"string"},"publicKeyJwk":{"description":"The public key in JWK format according to RFC7517. This public key is associated with the private\nkey with the associated ID.","allOf":[{"$ref":"#/definitions/jwx.PublicKeyJWK"}]},"type":{"$ref":"#/definitions/crypto.KeyType"}}},"pkg_server_router.GetManifestRequestResponse":{"type":"object","properties":{"manifestRequest":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_manifest_model.Request"}}},"pkg_server_router.GetPresentationDefinitionResponse":{"type":"object","properties":{"presentation_definition":{"$ref":"#/definitions/exchange.PresentationDefinition"}}},"pkg_server_router.GetReadinessResponse":{"type":"object","properties":{"serviceStatuses":{"description":"A map from the name of the service ot the status of that current service.","type":"object","additionalProperties":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_framework.Status"}},"status":{"description":"Overall status of the ssi service.","allOf":[{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_framework.Status"}]}}},"pkg_server_router.GetRequestResponse":{"type":"object","properties":{"presentationRequest":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Request"}}},"pkg_server_router.GetResponseResponse":{"type":"object","properties":{"credential_response":{"$ref":"#/definitions/manifest.CredentialResponse"},"responseJwt":{"type":"string"},"verifiableCredentials":{"description":"this is an interface type to union Data Integrity and JWT style VCs"}}},"pkg_server_router.GetSchemaResponse":{"type":"object","properties":{"credentialSchema":{"type":"string"},"schema":{"$ref":"#/definitions/schema.JSONSchema"}}},"pkg_server_router.GetSubmissionResponse":{"type":"object","required":["status"],"properties":{"reason":{"description":"The reason why the submission was approved or denied.","type":"string"},"status":{"description":"One of {` + "`" + `pending` + "`" + `, ` + "`" + `approved` + "`" + `, ` + "`" + `denied` + "`" + `, ` + "`" + `cancelled` + "`" + `}.","type":"string"},"verifiablePresentation":{"description":"The verifiable presentation containing the presentation_submission along with the credentials presented.","allOf":[{"$ref":"#/definitions/credential.VerifiablePresentation"}]}}},"pkg_server_router.ListApplicationsResponse":{"type":"object","properties":{"applications":{"type":"array","items":{"$ref":"#/definitions/manifest.CredentialApplication"}}}},"pkg_server_router.ListCredentialsResponse":{"type":"object","properties":{"credentials":{"description":"Array of credential containers.","type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_internal_credential.Container"}}}},"pkg_server_router.ListDIDMethodsResponse":{"type":"object","properties":{"method":{"type":"array","items":{"$ref":"#/definitions/did.Method"}}}},"pkg_server_router.ListDIDsByMethodResponse":{"type":"object","properties":{"dids":{"type":"array","items":{"$ref":"#/definitions/did.Document"}}}},"pkg_server_router.ListDefinitionsResponse":{"type":"object","properties":{"definitions":{"type":"array","items":{"$ref":"#/definitions/exchange.PresentationDefinition"}}}},"pkg_server_router.ListIssuanceTemplatesResponse":{"type":"object","properties":{"issuanceTemplates":{"type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_issuance.Template"}}}},"pkg_server_router.ListManifestRequestsResponse":{"type":"object","properties":{"manifestRequests":{"description":"The manifest requests matching the query.","type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_manifest_model.Request"}}}},"pkg_server_router.ListManifestResponse":{"type":"object","properties":{"credential_manifest":{"$ref":"#/definitions/manifest.CredentialManifest"},"id":{"type":"string"}}},"pkg_server_router.ListManifestsResponse":{"type":"object","properties":{"manifests":{"type":"array","items":{"$ref":"#/definitions/pkg_server_router.ListManifestResponse"}}}},"pkg_server_router.ListOperationsResponse":{"type":"object","properties":{"operations":{"type":"array","items":{"$ref":"#/definitions/pkg_server_router.Operation"}}}},"pkg_server_router.ListResponsesResponse":{"type":"object","properties":{"responses":{"type":"array","items":{"$ref":"#/definitions/manifest.CredentialResponse"}}}},"pkg_server_router.ListSchemasResponse":{"type":"object","properties":{"schemas":{"type":"array","items":{"$ref":"#/definitions/pkg_server_router.GetSchemaResponse"}}}},"pkg_server_router.ListSubmissionResponse":{"type":"object","properties":{"submissions":{"type":"array","items":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_presentation_model.Submission"}}}},"pkg_server_router.ListWebhookResponse":{"type":"object","properties":{"webhook":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_webhook.Webhook"}}},"pkg_server_router.ListWebhooksResponse":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/definitions/pkg_server_router.ListWebhookResponse"}}}},"pkg_server_router.Operation":{"type":"object","required":["done","id"],"properties":{"done":{"description":"Whether this operation has finished.","type":"boolean"},"id":{"description":"The name of the resource related to this operation. E.g. \"presentations/submissions/\u003cuuid\u003e\"","type":"string"},"result":{"description":"Populated if Done == true.","allOf":[{"$ref":"#/definitions/pkg_server_router.OperationResult"}]}}},"pkg_server_router.OperationResult":{"type":"object","properties":{"error":{"description":"Populated when there was an error with the operation.","type":"string"},"response":{"description":"Populated iff Error == \"\". The type should be specified in the calling APIs documentation."}}},"pkg_server_router.ResolveDIDResponse":{"type":"object","properties":{"didDocument":{"$ref":"#/definitions/did.Document"},"didDocumentMetadata":{"$ref":"#/definitions/resolution.DocumentMetadata"},"didResolutionMetadata":{"$ref":"#/definitions/resolution.Metadata"}}},"pkg_server_router.ReviewApplicationRequest":{"type":"object","properties":{"approved":{"type":"boolean"},"credentialOverrides":{"description":"Overrides to apply to the credentials that will be created. Keys are the ID that corresponds to an\nOutputDescriptor.ID from the manifest.","type":"object","additionalProperties":{"$ref":"#/definitions/github_com_tbd54566975_ssi-service_pkg_service_manifest_model.CredentialOverride"}},"reason":{"type":"string"}}},"pkg_server_router.ReviewSubmissionRequest":{"type":"object","required":["approved"],"properties":{"approved":{"type":"boolean"},"reason":{"type":"string"}}},"pkg_server_router.ReviewSubmissionResponse":{"type":"object","required":["status"],"properties":{"reason":{"description":"The reason why the submission was approved or denied.","type":"string"},"status":{"description":"One of {` + "`" + `pending` + "`" + `, ` + "`" + `approved` + "`" + `, ` + "`" + `denied` + "`" + `, ` + "`" + `cancelled` + "`" + `}.","type":"string"},"verifiablePresentation":{"description":"The verifiable presentation containing the presentation_submission along with the credentials presented.","allOf":[{"$ref":"#/definitions/credential.VerifiablePresentation"}]}}},"pkg_server_router.RevokeKeyResponse":{"type":"object","properties":{"id":{"type":"string"}}},"pkg_server_router.StoreKeyRequest":{"type":"object","required":["base58PrivateKey","controller","id","type"],"properties":{"base58PrivateKey":{"description":"Base58 encoding of the bytes that result from marshalling the private key using golang's implementation.","type":"string"},"controller":{"description":"See https://www.w3.org/TR/did-core/#did-controller","type":"string"},"id":{"description":"The ` + "`" + `id` + "`" + ` field is the unique identifier for this object. If set to a resolvable DID, the ssi-service will use\nthe private key encoded in the ` + "`" + `PrivateKeyBase58` + "`" + ` field of this object to sign objects issued or authored by this\nDID; otherwise, it will only be used to identify this object.","type":"string"},"type":{"description":"Identifies the cryptographic algorithm family used with the key.\nOne of the following: \"Ed25519\", \"X25519\", \"secp256k1\", \"P-224\", \"P-256\", \"P-384\", \"P-521\", \"RSA\".","allOf":[{"$ref":"#/definitions/crypto.KeyType"}]}}},"pkg_server_router.SubmitApplicationRequest":{"type":"object","required":["applicationJwt"],"properties":{"applicationJwt":{"description":"Contains the following properties:\nApplication manifestsdk.CredentialApplication ` + "`" + `json:\"credential_application\" validate:\"required\"` + "`" + `\nCredentials []interface{} ` + "`" + `json:\"vcs\" validate:\"required\"` + "`" + `","type":"string"}}},"pkg_server_router.SubmitApplicationResponse":{"type":"object","properties":{"credential_response":{"$ref":"#/definitions/manifest.CredentialResponse"},"responseJwt":{"type":"string"},"verifiableCredentials":{"description":"this is an any type to union Data Integrity and JWT style VCs","type":"array","items":{}}}},"pkg_server_router.UpdateCredentialStatusRequest":{"type":"object","properties":{"revoked":{"description":"The new revoked status of this credential. The status will be saved in the encodedList of the StatusList2021\ncredential associated with this VC.","type":"boolean"},"suspended":{"type":"boolean"}}},"pkg_server_router.UpdateCredentialStatusResponse":{"type":"object","properties":{"revoked":{"description":"The updated status of this credential.","type":"boolean"},"suspended":{"type":"boolean"}}},"pkg_server_router.VerifyCredentialRequest":{"type":"object","properties":{"credential":{"description":"A credential secured via data integrity. Must have the \"proof\" property set.","allOf":[{"$ref":"#/definitions/credential.VerifiableCredential"}]},"credentialJwt":{"description":"A JWT that encodes a credential.","type":"string"}}},"pkg_server_router.VerifyCredentialResponse":{"type":"object","properties":{"reason":{"description":"The reason why this credential couldn't be verified.","type":"string"},"verified":{"description":"Whether the credential was verified.","type":"boolean"}}},"rendering.ColorResource":{"type":"object","properties":{"color":{"description":"a HEX string color value (e.g. #00000)","type":"string"}}},"rendering.DataDisplay":{"type":"object","properties":{"description":{"$ref":"#/definitions/rendering.DisplayMappingObject"},"properties":{"type":"array","items":{"$ref":"#/definitions/rendering.LabeledDisplayMappingObject"}},"subtitle":{"$ref":"#/definitions/rendering.DisplayMappingObject"},"title":{"$ref":"#/definitions/rendering.DisplayMappingObject"}}},"rendering.DisplayMappingObject":{"type":"object","properties":{"fallback":{"type":"string"},"path":{"description":"Ifa path is present it must be an array of JSON Path string expressions\nand the schema property must also be present.","type":"array","items":{"type":"string"}},"schema":{"$ref":"#/definitions/rendering.DisplayMappingSchema"},"text":{"description":"If path is not present, the text value is required with no other properties","type":"string"}}},"rendering.DisplayMappingSchema":{"type":"object","required":["type"],"properties":{"format":{"description":"Must be present if the value of the type property is \"string\"","allOf":[{"$ref":"#/definitions/rendering.SchemaFormat"}]},"type":{"$ref":"#/definitions/rendering.SchemaType"}}},"rendering.EntityStyleDescriptor":{"type":"object","properties":{"background":{"$ref":"#/definitions/rendering.ColorResource"},"hero":{"$ref":"#/definitions/rendering.ImageResource"},"text":{"$ref":"#/definitions/rendering.ColorResource"},"thumbnail":{"$ref":"#/definitions/rendering.ImageResource"}}},"rendering.ImageResource":{"type":"object","required":["uri"],"properties":{"alt":{"description":"Describes the alternate text for a logo image","type":"string"},"uri":{"description":"Must be a valid URI string to an image resource","type":"string"}}},"rendering.LabeledDisplayMappingObject":{"type":"object","required":["label"],"properties":{"fallback":{"type":"string"},"label":{"type":"string"},"path":{"description":"Ifa path is present it must be an array of JSON Path string expressions\nand the schema property must also be present.","type":"array","items":{"type":"string"}},"schema":{"$ref":"#/definitions/rendering.DisplayMappingSchema"},"text":{"description":"If path is not present, the text value is required with no other properties","type":"string"}}},"rendering.SchemaFormat":{"type":"string","enum":["date-time","time","date","email","idn-email","hostname","idn-hostname","ipv4","ipv6","uri","uri-reference","iri","iri-reference"],"x-enum-varnames":["DateTimeFormat","TimeFormat","DateFormat","EmailFormat","IDNEmailFormat","HostnameFormat","IDNHostnameFormat","IPV4Format","IPV6Format","URIFormat","URIReferenceFormat","IRIFormat","IRIReferenceFormat"]},"rendering.SchemaType":{"type":"string","enum":["string","boolean","number","integer"],"x-enum-varnames":["StringType","BooleanType","NumberType","IntegerType"]},"resolution.DocumentMetadata":{"type":"object","properties":{"canonicalId":{"type":"string"},"created":{"type":"string"},"deactivated":{"type":"boolean"},"equivalentId":{"type":"string"},"nextUpdate":{"type":"string"},"nextVersionId":{"type":"string"},"updated":{"type":"string"},"versionId":{"type":"string"}}},"resolution.Error":{"type":"object","properties":{"code":{"type":"string"},"invalidDid":{"type":"boolean"},"notFound":{"type":"boolean"},"representationNotSupported":{"type":"boolean"}}},"resolution.Metadata":{"type":"object","properties":{"contentType":{"type":"string"},"error":{"$ref":"#/definitions/resolution.Error"}}},"schema.JSONSchema":{"type":"object","additionalProperties":{}},"time.Duration":{"type":"integer","enum":[-9223372036854775808,9223372036854775807,1,1000,1000000,1000000000,60000000000,3600000000000],"x-enum-varnames":["minDuration","maxDuration","Nanosecond","Microsecond","Millisecond","Second","Minute","Hour"]}}}` // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ diff --git a/doc/swagger.yaml b/doc/swagger.yaml index 3bd6ce23c..7d109c1f3 100644 --- a/doc/swagger.yaml +++ b/doc/swagger.yaml @@ -121,6 +121,8 @@ definitions: - P-384 - P-521 - RSA + - BLS12381G1 + - BLS12381G2 - Dilithium2 - Dilithium3 - Dilithium5 @@ -135,6 +137,8 @@ definitions: - P384 - P521 - RSA + - BLS12381G1 + - BLS12381G2 - Dilithium2 - Dilithium3 - Dilithium5 @@ -1178,34 +1182,31 @@ definitions: type: object pkg_server_router.CreateSchemaRequest: properties: - author: - type: string - authorKid: - description: AuthorKID represents the KID of the author's private key to sign - the schema. Required if sign is true. + description: + description: Description is an optional human-readable description for a schema type: string name: + description: Name is a human-readable name for a schema type: string schema: - $ref: '#/definitions/schema.JSONSchema' - sign: + allOf: + - $ref: '#/definitions/schema.JSONSchema' description: |- - Sign represents whether the schema should be signed by the author. Default is false. - If sign is true, the schema will be signed by the author's private key with the specified KID - type: boolean + Schema represents the JSON schema for the credential schema + If the schema has an $id field, it will be overwritten with an ID the service generates. + The schema must be against draft 2020-12, 2019-09, or 7. required: - - author - name - schema type: object pkg_server_router.CreateSchemaResponse: properties: + credentialSchema: + type: string id: type: string schema: - $ref: '#/definitions/schema.VCJSONSchema' - schemaJwt: - type: string + $ref: '#/definitions/schema.JSONSchema' type: object pkg_server_router.CreateSubmissionRequest: properties: @@ -1349,10 +1350,10 @@ definitions: type: object pkg_server_router.GetSchemaResponse: properties: - schema: - $ref: '#/definitions/schema.VCJSONSchema' - schemaJwt: + credentialSchema: type: string + schema: + $ref: '#/definitions/schema.JSONSchema' type: object pkg_server_router.GetSubmissionResponse: properties: @@ -1507,7 +1508,7 @@ definitions: didDocumentMetadata: $ref: '#/definitions/resolution.DocumentMetadata' didResolutionMetadata: - $ref: '#/definitions/resolution.ResolutionMetadata' + $ref: '#/definitions/resolution.Metadata' type: object pkg_server_router.ReviewApplicationRequest: properties: @@ -1640,22 +1641,6 @@ definitions: description: Whether the credential was verified. type: boolean type: object - pkg_server_router.VerifySchemaRequest: - properties: - schemaJwt: - type: string - required: - - schemaJwt - type: object - pkg_server_router.VerifySchemaResponse: - properties: - reason: - type: string - verified: - type: boolean - required: - - verified - type: object rendering.ColorResource: properties: color: @@ -1809,7 +1794,7 @@ definitions: versionId: type: string type: object - resolution.ResolutionError: + resolution.Error: properties: code: type: string @@ -1820,33 +1805,16 @@ definitions: representationNotSupported: type: boolean type: object - resolution.ResolutionMetadata: + resolution.Metadata: properties: contentType: type: string error: - $ref: '#/definitions/resolution.ResolutionError' + $ref: '#/definitions/resolution.Error' type: object schema.JSONSchema: additionalProperties: {} type: object - schema.VCJSONSchema: - properties: - author: - type: string - authored: - type: string - id: - type: string - name: - type: string - schema: - $ref: '#/definitions/schema.JSONSchema' - type: - type: string - version: - type: string - type: object time.Duration: enum: - -9223372036854775808 @@ -3372,7 +3340,7 @@ paths: description: Internal server error schema: type: string - summary: Create SchemaID + summary: Create Schema tags: - SchemaAPI /v1/schemas/{id}: @@ -3401,7 +3369,7 @@ paths: description: Internal server error schema: type: string - summary: Delete SchemaID + summary: Delete Schema tags: - SchemaAPI get: @@ -3425,33 +3393,7 @@ paths: description: Bad request schema: type: string - summary: Get SchemaID - tags: - - SchemaAPI - /v1/schemas/verification: - put: - consumes: - - application/json - description: Verify a given schema by its id - parameters: - - description: request body - in: body - name: request - required: true - schema: - $ref: '#/definitions/pkg_server_router.VerifySchemaRequest' - produces: - - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/pkg_server_router.VerifySchemaResponse' - "400": - description: Bad request - schema: - type: string - summary: Verify SchemaID + summary: Get Schema tags: - SchemaAPI /v1/webhooks: diff --git a/go.mod b/go.mod index b1bb37dad..9f00258ba 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/BurntSushi/toml v1.2.1 - github.com/TBD54566975/ssi-sdk v0.0.4-alpha + github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230526191213-380b671c2a1a github.com/alicebob/miniredis/v2 v2.30.2 github.com/ardanlabs/conf v1.5.0 github.com/benbjohnson/clock v1.3.5 @@ -35,12 +35,14 @@ require ( github.com/swaggo/swag/v2 v2.0.0-rc3 go.einride.tech/aip v0.60.0 go.etcd.io/bbolt v1.3.7 + go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.41.1 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.41.1 go.opentelemetry.io/otel v1.15.1 go.opentelemetry.io/otel/exporters/jaeger v1.15.1 go.opentelemetry.io/otel/sdk v1.15.1 go.opentelemetry.io/otel/trace v1.15.1 golang.org/x/crypto v0.9.0 + golang.org/x/term v0.8.0 google.golang.org/api v0.122.0 gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/h2non/gock.v1 v1.1.2 @@ -94,13 +96,14 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.6.8 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hyperledger/aries-framework-go v0.3.1 // indirect + github.com/hyperledger/aries-framework-go v0.3.2 // indirect github.com/hyperledger/aries-framework-go/component/kmscrypto v0.0.0-20230427134832-0c9969493bd3 // indirect github.com/hyperledger/aries-framework-go/component/log v0.0.0-20230427134832-0c9969493bd3 // indirect github.com/hyperledger/aries-framework-go/component/models v0.0.0-20230501135648-a9a7ad029347 // indirect github.com/hyperledger/aries-framework-go/spi v0.0.0-20230427134832-0c9969493bd3 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jorrizza/ed2curve25519 v0.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69 // indirect @@ -153,7 +156,6 @@ require ( github.com/ugorji/go/codec v1.2.11 // indirect github.com/yuin/gopher-lua v1.1.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.41.1 // indirect go.opentelemetry.io/otel/metric v0.38.1 // indirect golang.org/x/arch v0.3.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect @@ -161,7 +163,6 @@ require ( golang.org/x/net v0.10.0 // indirect golang.org/x/oauth2 v0.7.0 // indirect golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/tools v0.9.1 // indirect google.golang.org/appengine v1.6.7 // indirect diff --git a/go.sum b/go.sum index 41b752201..5035deb51 100644 --- a/go.sum +++ b/go.sum @@ -35,8 +35,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/TBD54566975/ssi-sdk v0.0.4-alpha h1:GbZG0S3xeaWQi2suWw2VjGRhM/S2RrIsfiubxSHlViE= -github.com/TBD54566975/ssi-sdk v0.0.4-alpha/go.mod h1:O4iANflxGCX0NbjHOhthq0X0il2ZYNMYlUnjEa0rsC0= +github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230526191213-380b671c2a1a h1:y8dmyhELNtnxolMNjBjddNVGeW0psdzCDoJJJwSBXJI= +github.com/TBD54566975/ssi-sdk v0.0.4-alpha.0.20230526191213-380b671c2a1a/go.mod h1:jnnNbOc+tAYoN603vvY7ZGZZ9Kn3VFSu1XK8qUCVSbM= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -80,8 +80,6 @@ github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 h1:KdUfX2zKommPRa+PD0sWZUyXe9w277ABlgELO7H04IM= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q= -github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.8.10 h1:XFSQg4/rwpQnNWSybNDr8oz6QtQY9uRGfRKDVWVsvP8= github.com/bytedance/sonic v1.8.10/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -284,8 +282,6 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= -github.com/go-playground/validator/v10 v10.13.0 h1:cFRQdfaSMCOSfGCCLB20MHvuoHb/s5G8L5pu2ppK5AQ= -github.com/go-playground/validator/v10 v10.13.0/go.mod h1:dwu7+CG8/CtBiJFZDz4e+5Upb6OLw04gtBYw0mcG/z4= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -655,8 +651,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= 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.3.1 h1:44hOqFdVtXPRmfxK1dHds1g1mouJFNeP1D/PBjDxRv8= -github.com/hyperledger/aries-framework-go v0.3.1/go.mod h1:SorUysWEBw+uyXhY5RAtg2iyNkWTIIPM8+Slkt1Spno= +github.com/hyperledger/aries-framework-go v0.3.2 h1:GsSUaSEW82cr5X8b3Qf90GAi37kmTKHqpPJLhar13X8= +github.com/hyperledger/aries-framework-go v0.3.2/go.mod h1:SorUysWEBw+uyXhY5RAtg2iyNkWTIIPM8+Slkt1Spno= github.com/hyperledger/aries-framework-go/component/kmscrypto v0.0.0-20230427134832-0c9969493bd3 h1:PCbDSujjQ6oTEnAHgtThNmbS7SPAYEDBlKOnZFE+Ujw= github.com/hyperledger/aries-framework-go/component/kmscrypto v0.0.0-20230427134832-0c9969493bd3/go.mod h1:aEk0vHBmZsAdDfXaI12Kg5ipZGiB3qNqgbPt/e/Hm2s= github.com/hyperledger/aries-framework-go/component/log v0.0.0-20230427134832-0c9969493bd3 h1:x5qFQraTX86z9GCwF28IxfnPm6QH5YgHaX+4x97Jwvw= @@ -721,6 +717,8 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jorrizza/ed2curve25519 v0.1.0 h1:P58ZEiVKW4vknYuGyOXuskMm82rTJyGhgRGrMRcCE8E= +github.com/jorrizza/ed2curve25519 v0.1.0/go.mod h1:27VPNk2FnNqLQNvvVymiX41VE/nokPyn5HHP7gtfYlo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -851,8 +849,6 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -976,8 +972,6 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv github.com/pelletier/go-toml v1.8.0 h1:Keo9qb7iRJs2voHvunFtuuYFsbWeOBh8/P9v/kVMFtw= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/pelletier/go-toml/v2 v2.0.7 h1:muncTPStnKRos5dpVKULv2FVd4bMOhNePj9CjgDb8Us= -github.com/pelletier/go-toml/v2 v2.0.7/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= @@ -1210,12 +1204,14 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.opentelemetry.io/contrib v0.18.0 h1:uqBh0brileIvG6luvBjdxzoFL8lxDGuhxJWsvK3BveI= go.opentelemetry.io/contrib v0.18.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.41.1 h1:F1wGw8hkRn5ttr4olo89WWC7yAclX4bb/ParlhfVFCw= go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.41.1/go.mod h1:PyReH9uu66TiB2IGfyJVRopiRqyw7afjLAZ+Gyw4LjI= go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.18.0/go.mod h1:iK1G0FgHurSJ/aYLg5LpnPI0pqdanM73S3dhyDp0Lk4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.41.1 h1:pX+lppB8PArapyhS6nBStyQmkaDUPWdQf0UmEGRCQ54= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.41.1/go.mod h1:2FmkXne0k9nkp27LD/m+uoh8dNlstsiCJ7PLc/S72aI= +go.opentelemetry.io/contrib/propagators/b3 v1.16.1 h1:Y9Dk1kR93eSHadRTkqnm+QyQVhHthCcvTkoP/Afh7+4= go.opentelemetry.io/otel v0.18.0/go.mod h1:PT5zQj4lTsR1YeARt8YNKcFb88/c2IKoSABK9mX0r78= go.opentelemetry.io/otel v1.15.1 h1:3Iwq3lfRByPaws0f6bU3naAqOR1n5IeDWd9390kWHa8= go.opentelemetry.io/otel v1.15.1/go.mod h1:mHHGEHVDLal6YrKMmk9LqC4a3sF5g+fHfrttQIB1NTc= @@ -1275,6 +1271,7 @@ golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= diff --git a/integration/testdata/schema-input.json b/integration/testdata/schema-input.json index 4bbeb0e84..5546010a2 100644 --- a/integration/testdata/schema-input.json +++ b/integration/testdata/schema-input.json @@ -1,55 +1,55 @@ { - "author":"did:example:123", - "name":"KYC", - "schema":{ - "$id":"kyc-schema-1.0", - "$schema":"https://json-schema.org/draft/2020-12/schema", - "description":"KYC Schema", - "type":"object", - "properties":{ - "id":{ - "type":"string" - }, - "givenName":{ - "type":"string" - }, - "additionalName":{ - "type":"string" - }, - "familyName":{ - "type":"string" - }, - "birthDate":{ - "type":"string" - }, - "postalAddress":{ - "type":"object", - "properties":{ - "addressCountry":{ - "type":"string" + "name": "KYC", + "description": "KYC Schema", + "schema": { + "$id": "kyc-schema-1.0", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "credentialSubject": { + "type": "object", + "properties": { + "id": { + "type": "string" }, - "addressLocality":{ - "type":"string" + "givenName": { + "type": "string" }, - "addressRegion":{ - "type":"string" + "additionalName": { + "type": "string" }, - "postalCode":{ - "type":"string" + "familyName": { + "type": "string" }, - "streetAddress":{ - "type":"string" + "birthDate": { + "type": "string" + }, + "postalAddress": { + "type": "object", + "properties": { + "addressCountry": { + "type": "string" + }, + "addressLocality": { + "type": "string" + }, + "addressRegion": { + "type": "string" + }, + "postalCode": { + "type": "string" + }, + "streetAddress": { + "type": "string" + } + } + }, + "taxId": { + "type": "string" } - } - }, - "taxId":{ - "type":"string" + }, + "additionalProperties": false } - }, - "required":[ - - ], - "additionalProperties":false - }, - "sign":false + } + } } \ No newline at end of file diff --git a/integration/testdata/schema-output.json b/integration/testdata/schema-output.json deleted file mode 100644 index 69097a845..000000000 --- a/integration/testdata/schema-output.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "id":"bc77954b-57fc-4d5c-bfff-a6acb2a17b60", - "schema":{ - "type":"https://w3c-ccg.github.io/vc-json-schemas/schema/2.0/schema.json", - "version":"1.0", - "id":"bc77954b-57fc-4d5c-bfff-a6acb2a17b60", - "name":"KYC", - "author":"did:example:123", - "authored":"2022-10-19T16:07:33Z", - "schema":{ - "$id":"kyc-schema-1.0", - "$schema":"https://json-schema.org/draft/2020-12/schema", - "additionalProperties":false, - "description":"KYC Schema", - "properties":{ - "additionalName":{ - "type":"string" - }, - "birthDate":{ - "type":"string" - }, - "familyName":{ - "type":"string" - }, - "givenName":{ - "type":"string" - }, - "id":{ - "type":"string" - }, - "postalAddress":{ - "type":"string" - }, - "taxID":{ - "type":"string" - } - }, - "required":[ - - ], - "type":"object" - } - } -} \ No newline at end of file diff --git a/internal/schema/resolver.go b/internal/schema/resolver.go index abfc1f00e..c1d023eed 100644 --- a/internal/schema/resolver.go +++ b/internal/schema/resolver.go @@ -8,5 +8,5 @@ import ( // Resolution is an interface that defines a generic method of resolving a schema type Resolution interface { - Resolve(ctx context.Context, id string) (*schema.VCJSONSchema, error) + Resolve(ctx context.Context, id string) (*schema.JSONSchema, error) } diff --git a/pkg/server/router/credential_test.go b/pkg/server/router/credential_test.go index d1d928b47..4704016bb 100644 --- a/pkg/server/router/credential_test.go +++ b/pkg/server/router/credential_test.go @@ -139,17 +139,7 @@ func TestCredentialRouter(t *testing.T) { assert.Contains(tt, err.Error(), "schema not found with id: https://test-schema.com") // create schema - emailSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "email": map[string]any{ - "type": "string", - }, - }, - "required": []any{"email"}, - "additionalProperties": false, - } - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, Name: "simple schema", Schema: emailSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, Name: "simple schema", Schema: getEmailSchema()}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -205,7 +195,7 @@ func TestCredentialRouter(t *testing.T) { bolt := setupTestDB(tt) assert.NotEmpty(tt, bolt) - serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential"}} + serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "v1/credentials"}} keyStoreService := testKeyStoreService(tt, bolt) didService := testDIDService(tt, bolt, keyStoreService) schemaService := testSchemaService(tt, bolt, keyStoreService, didService) @@ -223,18 +213,7 @@ func TestCredentialRouter(t *testing.T) { assert.NotEmpty(tt, issuerDID) // create a schema - emailSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "email": map[string]any{ - "type": "string", - }, - }, - "required": []any{"email"}, - "additionalProperties": false, - } - - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, Name: "simple schema", Schema: emailSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, Name: "simple schema", Schema: getEmailSchema()}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -290,7 +269,7 @@ func TestCredentialRouter(t *testing.T) { // Cred with same <issuer, schema> pair share the same statusListCredential assert.Equal(tt, credStatusMapTwo["statusListCredential"], credStatusMap["statusListCredential"]) - createdSchemaTwo, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, Name: "simple schema", Schema: emailSchema}) + createdSchemaTwo, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, Name: "simple schema", Schema: getEmailSchema()}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchemaTwo) @@ -325,7 +304,7 @@ func TestCredentialRouter(t *testing.T) { bolt := setupTestDB(tt) assert.NotEmpty(tt, bolt) - serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential"}} + serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "/v1/credentials"}} keyStoreService := testKeyStoreService(tt, bolt) didService := testDIDService(tt, bolt, keyStoreService) schemaService := testSchemaService(tt, bolt, keyStoreService, didService) @@ -393,18 +372,8 @@ func TestCredentialRouter(t *testing.T) { // Cred with same <issuer, schema> pair share the same statusListCredential assert.Equal(tt, credStatusMapTwo["statusListCredential"], credStatusMap["statusListCredential"]) - emailSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "email": map[string]any{ - "type": "string", - }, - }, - "required": []any{"email"}, - "additionalProperties": false, - } - - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, Name: "simple schema", Schema: emailSchema}) + // create schema + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, Name: "simple schema", Schema: getEmailSchema()}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -439,7 +408,7 @@ func TestCredentialRouter(t *testing.T) { bolt := setupTestDB(tt) assert.NotEmpty(tt, bolt) - serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "http://localhost:1234"}} + serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "http://localhost:1234/v1/credentials"}} keyStoreService := testKeyStoreService(tt, bolt) didService := testDIDService(tt, bolt, keyStoreService) schemaService := testSchemaService(tt, bolt, keyStoreService, didService) @@ -456,18 +425,7 @@ func TestCredentialRouter(t *testing.T) { assert.NotEmpty(tt, issuerDID) // create a schema - emailSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "email": map[string]any{ - "type": "string", - }, - }, - "required": []any{"email"}, - "additionalProperties": false, - } - - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, Name: "simple schema", Schema: emailSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, Name: "simple schema", Schema: getEmailSchema()}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -570,7 +528,7 @@ func TestCredentialRouter(t *testing.T) { bolt := setupTestDB(tt) assert.NotEmpty(tt, bolt) - serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "http://localhost:1234"}} + serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "http://localhost:1234/v1/credentials"}} keyStoreService := testKeyStoreService(tt, bolt) didService := testDIDService(tt, bolt, keyStoreService) schemaService := testSchemaService(tt, bolt, keyStoreService, didService) @@ -587,18 +545,7 @@ func TestCredentialRouter(t *testing.T) { assert.NotEmpty(tt, issuerDID) // create a schema - emailSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "email": map[string]any{ - "type": "string", - }, - }, - "required": []any{"email"}, - "additionalProperties": false, - } - - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, Name: "simple schema", Schema: emailSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, Name: "simple schema", Schema: getEmailSchema()}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -701,7 +648,7 @@ func TestCredentialRouter(t *testing.T) { bolt := setupTestDB(tt) assert.NotEmpty(tt, bolt) - serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "http://localhost:1234"}} + serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "http://localhost:1234/v1/credentials"}} keyStoreService := testKeyStoreService(tt, bolt) didService := testDIDService(tt, bolt, keyStoreService) schemaService := testSchemaService(tt, bolt, keyStoreService, didService) @@ -718,18 +665,7 @@ func TestCredentialRouter(t *testing.T) { assert.NotEmpty(tt, issuerDID) // create a schema - emailSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "email": map[string]any{ - "type": "string", - }, - }, - "required": []any{"email"}, - "additionalProperties": false, - } - - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, Name: "simple schema", Schema: emailSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, Name: "simple schema", Schema: getEmailSchema()}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -1086,7 +1022,7 @@ func createCredServicePrereqs(tt *testing.T) (issuer, issuerKID, schemaID string bolt := setupTestDB(tt) require.NotEmpty(tt, bolt) - serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "http://localhost:1234"}} + serviceConfig := config.CredentialServiceConfig{BaseServiceConfig: &config.BaseServiceConfig{Name: "credential", ServiceEndpoint: "http://localhost:1234/v1/credentials"}} keyStoreService := testKeyStoreService(tt, bolt) didService := testDIDService(tt, bolt, keyStoreService) schemaService := testSchemaService(tt, bolt, keyStoreService, didService) @@ -1104,20 +1040,27 @@ func createCredServicePrereqs(tt *testing.T) (issuer, issuerKID, schemaID string require.NotEmpty(tt, issuerDID) // create a schema - emailSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "email": map[string]any{ - "type": "string", - }, - }, - "required": []any{"email"}, - "additionalProperties": false, - } - - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, Name: "simple schema", Schema: emailSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, Name: "simple schema", Schema: getEmailSchema()}) require.NoError(tt, err) require.NotEmpty(tt, createdSchema) return issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID, *credService } + +func getEmailSchema() map[string]any { + return map[string]any{ + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", + "properties": map[string]any{ + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "email": map[string]any{ + "type": "string", + }, + }, + "required": []any{"email"}, + }, + }, + } +} diff --git a/pkg/server/router/did.go b/pkg/server/router/did.go index 72cf63dcf..f01b907b2 100644 --- a/pkg/server/router/did.go +++ b/pkg/server/router/did.go @@ -279,9 +279,9 @@ func (dr DIDRouter) ListDIDsByMethod(c *gin.Context) { } type ResolveDIDResponse struct { - ResolutionMetadata *resolution.ResolutionMetadata `json:"didResolutionMetadata,omitempty"` - DIDDocument *didsdk.Document `json:"didDocument"` - DIDDocumentMetadata *resolution.DocumentMetadata `json:"didDocumentMetadata,omitempty"` + ResolutionMetadata *resolution.Metadata `json:"didResolutionMetadata,omitempty"` + DIDDocument *didsdk.Document `json:"didDocument"` + DIDDocumentMetadata *resolution.DocumentMetadata `json:"didDocumentMetadata,omitempty"` } // SoftDeleteDIDByMethod godoc diff --git a/pkg/server/router/manifest_test.go b/pkg/server/router/manifest_test.go index d4f25ecff..69e1f50e5 100644 --- a/pkg/server/router/manifest_test.go +++ b/pkg/server/router/manifest_test.go @@ -12,6 +12,7 @@ import ( "github.com/TBD54566975/ssi-sdk/did/key" "github.com/google/uuid" "github.com/stretchr/testify/assert" + "github.com/tbd54566975/ssi-service/pkg/service/common" "github.com/tbd54566975/ssi-service/pkg/service/manifest/model" @@ -76,16 +77,25 @@ func TestManifestRouter(t *testing.T) { // create a schema for the creds to be issued against licenseSchema := map[string]any{ - "type": "object", + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "id": map[string]any{ + "type": "string", + }, + "licenseType": map[string]any{ + "type": "string", + }, + }, + "required": []any{"licenseType", "id"}, }, }, - "additionalProperties": true, } kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -155,6 +165,14 @@ func TestManifestRouter(t *testing.T) { ID: storage.StatusObjectID(createdApplicationResponseOp.ID), Approved: true, Reason: "ApprovalMan is here", + CredentialOverrides: map[string]model.CredentialOverride{ + "id1": { + Data: map[string]any{"licenseType": "Class D"}, + }, + "id2": { + Data: map[string]any{"licenseType": "Class D"}, + }, + }, }) assert.NoError(tt, err) assert.NotEmpty(tt, createdManifest) @@ -191,7 +209,7 @@ func getValidManifestRequest(issuerDID, issuerKID, schemaID string) model.Create ID: "id123", InputDescriptors: []exchange.InputDescriptor{ { - ID: "test-id", + ID: "license-type", Constraints: &exchange.Constraints{ Fields: []exchange.Field{ { diff --git a/pkg/server/router/presentation_test.go b/pkg/server/router/presentation_test.go index 6b031a73b..94e524c8a 100644 --- a/pkg/server/router/presentation_test.go +++ b/pkg/server/router/presentation_test.go @@ -11,9 +11,9 @@ import ( "github.com/TBD54566975/ssi-sdk/crypto" didsdk "github.com/TBD54566975/ssi-sdk/did" "github.com/goccy/go-json" - "github.com/mr-tron/base58" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tbd54566975/ssi-service/config" "github.com/tbd54566975/ssi-service/internal/keyaccess" "github.com/tbd54566975/ssi-service/pkg/service/common" @@ -50,9 +50,9 @@ func TestPresentationDefinitionService(t *testing.T) { KeyType: crypto.Ed25519, }) require.NoError(t, err) - pubKeyBytes, err := base58.Decode(authorDID.DID.VerificationMethod[0].PublicKeyBase58) - require.NoError(t, err) - pubKey, err := crypto.BytesToPubKey(pubKeyBytes, crypto.Ed25519) + pubKeyJWK := authorDID.DID.VerificationMethod[0].PublicKeyJWK + require.NotEmpty(t, pubKeyJWK) + pubKey, err := pubKeyJWK.ToPublicKey() require.NoError(t, err) ka, err := keyaccess.NewJWKKeyAccessVerifier(authorDID.DID.ID, authorDID.DID.ID, pubKey) require.NoError(t, err) diff --git a/pkg/server/router/schema.go b/pkg/server/router/schema.go index bc05b67e0..cf060d35e 100644 --- a/pkg/server/router/schema.go +++ b/pkg/server/router/schema.go @@ -30,26 +30,34 @@ func NewSchemaRouter(s svcframework.Service) (*SchemaRouter, error) { } type CreateSchemaRequest struct { - Author string `json:"author" validate:"required"` - Name string `json:"name" validate:"required"` + // Name is a human-readable name for a schema + Name string `json:"name" validate:"required"` + // Description is an optional human-readable description for a schema + Description string `json:"description,omitempty"` + // Schema represents the JSON schema for the credential schema + // If the schema has an $id field, it will be overwritten with an ID the service generates. + // The schema must be against draft 2020-12, 2019-09, or 7. Schema schemalib.JSONSchema `json:"schema" validate:"required"` + // TODO(gabe): re-enable in https://github.com/TBD54566975/ssi-service/issues/493 // Sign represents whether the schema should be signed by the author. Default is false. - // If sign is true, the schema will be signed by the author's private key with the specified KID - Sign bool `json:"sign"` - // AuthorKID represents the KID of the author's private key to sign the schema. Required if sign is true. - AuthorKID string `json:"authorKid"` + // If sign is true, the schema will be signed by the issuer's private key with the specified KID + // Sign bool `json:"sign,omitempty"` + // Issuer represents the DID of the issuer for the schema if it's signed. Required if sign is true. + // Issuer string `json:"issuer,omitempty"` + // IssuerKID represents the KID of the issuer's private key to sign the schema. Required if sign is true. + // IssuerKID string `json:"issuerKid,omitempty"` } type CreateSchemaResponse struct { - ID string `json:"id"` - Schema schemalib.VCJSONSchema `json:"schema"` - SchemaJWT *keyaccess.JWT `json:"schemaJwt,omitempty"` + ID string `json:"id"` + Schema schemalib.JSONSchema `json:"schema"` + CredentialSchema *keyaccess.JWT `json:"credentialSchema,omitempty"` } // CreateSchema godoc // -// @Summary Create SchemaID +// @Summary Create Schema // @Description Create schema // @Tags SchemaAPI // @Accept json @@ -72,27 +80,33 @@ func (sr SchemaRouter) CreateSchema(c *gin.Context) { return } - if request.Sign && request.AuthorKID == "" { - errMsg := "cannot sign schema without authorKID" - framework.LoggingRespondErrMsg(c, errMsg, http.StatusBadRequest) - return + // if request.Sign && (request.Issuer == "" || request.IssuerKID == "") { + // errMsg := "cannot sign schema without an issuer DID and KID" + // framework.LoggingRespondErrMsg(c, errMsg, http.StatusBadRequest) + // return + // } + + req := schema.CreateSchemaRequest{ + Name: request.Name, + Description: request.Description, + Schema: request.Schema, + // Sign: request.Sign, + // Issuer: request.Issuer, + // IssuerKID: request.IssuerKID, } - - req := schema.CreateSchemaRequest{Author: request.Author, AuthorKID: request.AuthorKID, Name: request.Name, Schema: request.Schema, Sign: request.Sign} createSchemaResponse, err := sr.service.CreateSchema(c, req) if err != nil { - errMsg := fmt.Sprintf("could not create schema with authoring DID<%s> and KID<%s>", request.Author, request.AuthorKID) - framework.LoggingRespondErrWithMsg(c, err, errMsg, http.StatusInternalServerError) + framework.LoggingRespondErrWithMsg(c, err, "could not create schema", http.StatusInternalServerError) return } - resp := CreateSchemaResponse{ID: createSchemaResponse.ID, Schema: createSchemaResponse.Schema, SchemaJWT: createSchemaResponse.SchemaJWT} + resp := CreateSchemaResponse{ID: createSchemaResponse.ID, Schema: createSchemaResponse.Schema} framework.Respond(c, resp, http.StatusCreated) } // GetSchema godoc // -// @Summary Get SchemaID +// @Summary Get Schema // @Description Get a schema by its ID // @Tags SchemaAPI // @Accept json @@ -117,7 +131,7 @@ func (sr SchemaRouter) GetSchema(c *gin.Context) { return } - resp := GetSchemaResponse{Schema: gotSchema.Schema, SchemaJWT: gotSchema.SchemaJWT} + resp := GetSchemaResponse{Schema: gotSchema.Schema} framework.Respond(c, resp, http.StatusOK) return } @@ -154,52 +168,13 @@ func (sr SchemaRouter) ListSchemas(c *gin.Context) { } type GetSchemaResponse struct { - Schema schemalib.VCJSONSchema `json:"schema,omitempty"` - SchemaJWT *keyaccess.JWT `json:"schemaJwt,omitempty"` -} - -type VerifySchemaRequest struct { - SchemaJWT keyaccess.JWT `json:"schemaJwt" validate:"required"` -} - -type VerifySchemaResponse struct { - Verified bool `json:"verified" validate:"required"` - Reason string `json:"reason,omitempty"` -} - -// VerifySchema godoc -// -// @Summary Verify SchemaID -// @Description Verify a given schema by its id -// @Tags SchemaAPI -// @Accept json -// @Produce json -// @Param request body VerifySchemaRequest true "request body" -// @Success 200 {object} VerifySchemaResponse -// @Failure 400 {string} string "Bad request" -// @Router /v1/schemas/verification [put] -func (sr SchemaRouter) VerifySchema(c *gin.Context) { - var request VerifySchemaRequest - if err := framework.Decode(c.Request, &request); err != nil { - errMsg := "invalid verify schema request" - framework.LoggingRespondErrWithMsg(c, err, errMsg, http.StatusBadRequest) - return - } - - verificationResult, err := sr.service.VerifySchema(c, schema.VerifySchemaRequest{SchemaJWT: request.SchemaJWT}) - if err != nil { - errMsg := "could not verify schema" - framework.LoggingRespondErrWithMsg(c, err, errMsg, http.StatusInternalServerError) - return - } - - resp := VerifySchemaResponse{Verified: verificationResult.Verified, Reason: verificationResult.Reason} - framework.Respond(c, resp, http.StatusOK) + Schema schemalib.JSONSchema `json:"schema,omitempty"` + CredentialSchema *keyaccess.JWT `json:"credentialSchema,omitempty"` } // DeleteSchema godoc // -// @Summary Delete SchemaID +// @Summary Delete Schema // @Description Delete a schema by its ID // @Tags SchemaAPI // @Accept json diff --git a/pkg/server/router/schema_test.go b/pkg/server/router/schema_test.go index dc4fbf3f4..031e06af9 100644 --- a/pkg/server/router/schema_test.go +++ b/pkg/server/router/schema_test.go @@ -4,12 +4,9 @@ import ( "context" "testing" - "github.com/TBD54566975/ssi-sdk/crypto" - didsdk "github.com/TBD54566975/ssi-sdk/did" "github.com/stretchr/testify/assert" "github.com/tbd54566975/ssi-service/config" - "github.com/tbd54566975/ssi-service/pkg/service/did" "github.com/tbd54566975/ssi-service/pkg/service/framework" "github.com/tbd54566975/ssi-service/pkg/service/schema" ) @@ -30,7 +27,7 @@ func TestSchemaRouter(t *testing.T) { assert.Contains(tt, err.Error(), "could not create schema router with service type: test") }) - t.Run("SchemaID Service Test", func(tt *testing.T) { + t.Run("Schema Service Test", func(tt *testing.T) { bolt := setupTestDB(tt) assert.NotEmpty(tt, bolt) @@ -57,21 +54,31 @@ func TestSchemaRouter(t *testing.T) { // create a schema simpleSchema := map[string]any{ - "type": "object", + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", "properties": map[string]any{ - "foo": map[string]any{ - "type": "string", + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "id": map[string]any{ + "type": "string", + }, + "firstName": map[string]any{ + "type": "string", + }, + "lastName": map[string]any{ + "type": "string", + }, + }, + "required": []any{"firstName", "lastName"}, }, }, - "required": []any{"foo"}, - "additionalProperties": false, } - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: "me", Name: "simple schema", Schema: simpleSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: "me", Name: "simple schema", Schema: simpleSchema}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) assert.NotEmpty(tt, createdSchema.ID) - assert.Equal(tt, "me", createdSchema.Schema.Author) - assert.Equal(tt, "simple schema", createdSchema.Schema.Name) + assert.Equal(tt, "simple schema", createdSchema.Schema.Name()) // get schema by ID gotSchema, err := schemaService.GetSchema(context.Background(), schema.GetSchemaRequest{ID: createdSchema.ID}) @@ -86,12 +93,11 @@ func TestSchemaRouter(t *testing.T) { assert.Len(tt, gotSchemas.Schemas, 1) // store another - createdSchema, err = schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: "me", Name: "simple schema 2", Schema: simpleSchema}) + createdSchema, err = schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: "me", Name: "simple schema 2", Schema: simpleSchema}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) assert.NotEmpty(tt, createdSchema.ID) - assert.Equal(tt, "me", createdSchema.Schema.Author) - assert.Equal(tt, "simple schema 2", createdSchema.Schema.Name) + assert.Equal(tt, "simple schema 2", createdSchema.Schema.Name()) // get all schemas, expect two gotSchemas, err = schemaService.ListSchemas(context.Background()) @@ -116,7 +122,7 @@ func TestSchemaRouter(t *testing.T) { func TestSchemaSigning(t *testing.T) { - t.Run("Unsigned SchemaID Test", func(tt *testing.T) { + t.Run("Unsigned Schema Test", func(tt *testing.T) { bolt := setupTestDB(tt) assert.NotEmpty(tt, bolt) @@ -133,54 +139,30 @@ func TestSchemaSigning(t *testing.T) { // create a schema and don't sign it simpleSchema := map[string]any{ - "type": "object", + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", "properties": map[string]any{ - "foo": map[string]any{ - "type": "string", + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "id": map[string]any{ + "type": "string", + }, + "firstName": map[string]any{ + "type": "string", + }, + "lastName": map[string]any{ + "type": "string", + }, + }, + "required": []any{"firstName", "lastName"}, }, }, - "required": []any{"foo"}, - "additionalProperties": false, } - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: "me", Name: "simple schema", Schema: simpleSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: "me", Name: "simple schema", Schema: simpleSchema}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) assert.NotEmpty(tt, createdSchema.ID) - assert.Empty(tt, createdSchema.SchemaJWT) - assert.Equal(tt, "me", createdSchema.Schema.Author) - assert.Equal(tt, "simple schema", createdSchema.Schema.Name) - - // missing kid - createdSchema, err = schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: "me", Name: "simple schema", Schema: simpleSchema, Sign: true}) - assert.Error(tt, err) - assert.Empty(tt, createdSchema) - assert.Contains(tt, err.Error(), "could not get key for signing schema for authorKID<>: getting key with id:") - - // create an author DID - authorDID, err := didService.CreateDIDByMethod(context.Background(), did.CreateDIDRequest{ - Method: didsdk.KeyMethod, - KeyType: crypto.Ed25519, - }) - assert.NoError(tt, err) - assert.NotEmpty(tt, authorDID) - - kid := authorDID.DID.VerificationMethod[0].ID - createdSchema, err = schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: authorDID.DID.ID, AuthorKID: kid, Name: "simple schema", Schema: simpleSchema, Sign: true}) - assert.NoError(tt, err) - assert.NotEmpty(tt, createdSchema) - assert.NotEmpty(tt, createdSchema.SchemaJWT) - - // verify the schema - verifiedSchema, err := schemaService.VerifySchema(context.Background(), schema.VerifySchemaRequest{SchemaJWT: *createdSchema.SchemaJWT}) - assert.NoError(tt, err) - assert.NotEmpty(tt, verifiedSchema) - assert.True(tt, verifiedSchema.Verified) - - // verify a bad schema - verifiedSchema, err = schemaService.VerifySchema(context.Background(), schema.VerifySchemaRequest{SchemaJWT: "bad"}) - assert.NoError(tt, err) - assert.NotEmpty(tt, verifiedSchema) - assert.False(tt, verifiedSchema.Verified) - assert.Contains(tt, verifiedSchema.Reason, "could not verify schema") + assert.Equal(tt, "simple schema", createdSchema.Schema.Name()) }) } diff --git a/pkg/server/server.go b/pkg/server/server.go index 1fad8d741..dea06539f 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -79,6 +79,9 @@ func NewSSIServer(shutdown chan os.Signal, cfg config.SSIServiceConfig) (*SSISer // register all v1 routers v1 := engine.Group(V1Prefix) + if err = KeyStoreAPI(v1, ssi.KeyStore); err != nil { + return nil, sdkutil.LoggingErrorMsg(err, "unable to instantiate KeyStore API") + } if err = DecentralizedIdentityAPI(v1, ssi.DID, ssi.Webhook); err != nil { return nil, sdkutil.LoggingErrorMsg(err, "unable to instantiate DID API") } @@ -88,15 +91,12 @@ func NewSSIServer(shutdown chan os.Signal, cfg config.SSIServiceConfig) (*SSISer if err = CredentialAPI(v1, ssi.Credential, ssi.Webhook); err != nil { return nil, sdkutil.LoggingErrorMsg(err, "unable to instantiate Credential API") } - if err = PresentationAPI(v1, ssi.Presentation, ssi.Webhook); err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "unable to instantiate Presentation API") - } - if err = KeyStoreAPI(v1, ssi.KeyStore); err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "unable to instantiate KeyStore API") - } if err = OperationAPI(v1, ssi.Operation); err != nil { return nil, sdkutil.LoggingErrorMsg(err, "unable to instantiate Operation API") } + if err = PresentationAPI(v1, ssi.Presentation, ssi.Webhook); err != nil { + return nil, sdkutil.LoggingErrorMsg(err, "unable to instantiate Presentation API") + } if err = ManifestAPI(v1, ssi.Manifest, ssi.Webhook); err != nil { return nil, sdkutil.LoggingErrorMsg(err, "unable to instantiate Manifest API") } @@ -171,7 +171,6 @@ func SchemaAPI(rg *gin.RouterGroup, service svcframework.Service, webhookService schemaAPI.PUT("", middleware.Webhook(webhookService, webhook.Schema, webhook.Create), schemaRouter.CreateSchema) schemaAPI.GET("/:id", schemaRouter.GetSchema) schemaAPI.GET("", schemaRouter.ListSchemas) - schemaAPI.PUT(VerificationPath, schemaRouter.VerifySchema) schemaAPI.DELETE("/:id", middleware.Webhook(webhookService, webhook.Schema, webhook.Delete), schemaRouter.DeleteSchema) return } diff --git a/pkg/server/server_credential_test.go b/pkg/server/server_credential_test.go index 974f95c39..9f7935267 100644 --- a/pkg/server/server_credential_test.go +++ b/pkg/server/server_credential_test.go @@ -105,7 +105,7 @@ func TestCredentialAPI(t *testing.T) { assert.Equal(tt, resp.Credential.Issuer, issuerDID.DID.ID) }) - t.Run("Test Create Credential with SchemaID", func(tt *testing.T) { + t.Run("Test Create Credential with Schema", func(tt *testing.T) { bolt := setupTestDB(tt) require.NotEmpty(tt, bolt) @@ -123,19 +123,27 @@ func TestCredentialAPI(t *testing.T) { // create a schema simpleSchema := map[string]any{ - "type": "object", + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", "properties": map[string]any{ - "firstName": map[string]any{ - "type": "string", - }, - "lastName": map[string]any{ - "type": "string", + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "id": map[string]any{ + "type": "string", + }, + "firstName": map[string]any{ + "type": "string", + }, + "lastName": map[string]any{ + "type": "string", + }, + }, + "required": []any{"firstName", "lastName"}, }, }, - "required": []any{"firstName", "lastName"}, - "additionalProperties": false, } - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: "me", Name: "simple schema", Schema: simpleSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: "me", Name: "simple schema", Schema: simpleSchema}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -279,7 +287,7 @@ func TestCredentialAPI(t *testing.T) { assert.Equal(tt, resp.Credential.ID, getCredResp.ID) }) - t.Run("Test Get Credential By SchemaID", func(tt *testing.T) { + t.Run("Test Get Credential By Schema", func(tt *testing.T) { bolt := setupTestDB(tt) require.NotEmpty(tt, bolt) @@ -299,19 +307,27 @@ func TestCredentialAPI(t *testing.T) { // create a schema simpleSchema := map[string]any{ - "type": "object", + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", "properties": map[string]any{ - "firstName": map[string]any{ - "type": "string", - }, - "lastName": map[string]any{ - "type": "string", + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "id": map[string]any{ + "type": "string", + }, + "firstName": map[string]any{ + "type": "string", + }, + "lastName": map[string]any{ + "type": "string", + }, + }, + "required": []any{"firstName", "lastName"}, }, }, - "required": []any{"firstName", "lastName"}, - "additionalProperties": false, } - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: "me", Name: "simple schema", Schema: simpleSchema}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: "me", Name: "simple schema", Schema: simpleSchema}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) diff --git a/pkg/server/server_did_test.go b/pkg/server/server_did_test.go index 105d881ef..8ed00b0de 100644 --- a/pkg/server/server_did_test.go +++ b/pkg/server/server_did_test.go @@ -8,7 +8,6 @@ import ( "github.com/TBD54566975/ssi-sdk/crypto" didsdk "github.com/TBD54566975/ssi-sdk/did" - "github.com/TBD54566975/ssi-sdk/did/ion" "github.com/goccy/go-json" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -202,7 +201,7 @@ func TestDIDAPI(t *testing.T) { w = httptest.NewRecorder() // good options - options := did.CreateIONDIDOptions{ServiceEndpoints: []ion.Service{{ID: "test", Type: "test", ServiceEndpoint: "test"}}} + options := did.CreateIONDIDOptions{ServiceEndpoints: []didsdk.Service{{ID: "test", Type: "test", ServiceEndpoint: "test"}}} // with body, bad key type createDIDRequest = router.CreateDIDByMethodRequest{KeyType: "bad", Options: options} diff --git a/pkg/server/server_issuance_test.go b/pkg/server/server_issuance_test.go index 4a19c36de..515312fb5 100644 --- a/pkg/server/server_issuance_test.go +++ b/pkg/server/server_issuance_test.go @@ -45,7 +45,7 @@ func TestIssuanceRouter(t *testing.T) { Credentials: []issuance.CredentialTemplate{ { ID: "output_descriptor_1", - Schema: createdSchema.Schema.ID, + Schema: createdSchema.ID, Data: issuance.ClaimTemplates{ "foo": "bar", "hello": "$.vcsomething.something", @@ -116,7 +116,7 @@ func TestIssuanceRouter(t *testing.T) { Credentials: []issuance.CredentialTemplate{ { ID: "", - Schema: createdSchema.Schema.ID, + Schema: createdSchema.ID, Data: issuance.ClaimTemplates{ "foo": "bar", "hello": "$.vcsomething.something", @@ -140,7 +140,7 @@ func TestIssuanceRouter(t *testing.T) { Credentials: []issuance.CredentialTemplate{ { ID: "output_descriptor_1", - Schema: createdSchema.Schema.ID, + Schema: createdSchema.ID, Data: issuance.ClaimTemplates{ "foo": "bar", "hello": "$.vcsomething.something", @@ -249,7 +249,7 @@ func TestIssuanceRouter(t *testing.T) { Credentials: []issuance.CredentialTemplate{ { ID: "output_descriptor_1", - Schema: createdSchema.Schema.ID, + Schema: createdSchema.ID, Data: issuance.ClaimTemplates{ "foo": "bar", "hello": "$.vcsomething.something", @@ -371,7 +371,7 @@ func createSimpleTemplate(t *testing.T, manifest *model.CreateManifestResponse, Credentials: []issuance.CredentialTemplate{ { ID: "output_descriptor_1", - Schema: createdSchema.Schema.ID, + Schema: createdSchema.ID, Data: issuance.ClaimTemplates{ "foo": "bar", "hello": "$.vcsomething.something", @@ -409,16 +409,25 @@ func setupAllThings(t *testing.T) (*did.CreateDIDResponse, *schema.CreateSchemaR require.NoError(t, err) licenseSchema := map[string]any{ - "type": "object", + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "id": map[string]any{ + "type": "string", + }, + "licenseType": map[string]any{ + "type": "string", + }, + }, + "required": []any{"licenseType", "id"}, }, }, - "additionalProperties": true, } keyID := issuerResp.DID.VerificationMethod[0].ID - createdSchema, err := schemaSvc.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerResp.DID.ID, AuthorKID: keyID, Name: "license schema", Schema: licenseSchema, Sign: true}) + createdSchema, err := schemaSvc.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerResp.DID.ID, IssuerKID: keyID, Name: "license schema", Schema: licenseSchema, Sign: true}) require.NoError(t, err) sillyName := "some silly name" @@ -432,7 +441,7 @@ func setupAllThings(t *testing.T) (*did.CreateDIDResponse, *schema.CreateSchemaR OutputDescriptors: []manifestsdk.OutputDescriptor{ { ID: "output_descriptor_1", - Schema: createdSchema.Schema.ID, + Schema: createdSchema.ID, }, }, }) diff --git a/pkg/server/server_manifest_test.go b/pkg/server/server_manifest_test.go index cc2293d79..847211e62 100644 --- a/pkg/server/server_manifest_test.go +++ b/pkg/server/server_manifest_test.go @@ -64,22 +64,13 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, issuerDID) // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) @@ -152,22 +143,13 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, issuerDID) // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) @@ -213,22 +195,13 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, issuerDID) // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) requestValue := newRequestValue(tt, createManifestRequest) req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) @@ -308,22 +281,13 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, issuerDID) // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + createdSchema, err := schemaService.CreateSchema(context.Background(), schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) requestValue := newRequestValue(tt, createManifestRequest) req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) @@ -396,22 +360,20 @@ func TestManifestAPI(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, applicantDID) - // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } + // create a schema for the creds to be issued against, needed for the application kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema( + licenseApplicationSchema, err := schemaService.CreateSchema( context.Background(), - schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license application schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) - assert.NotEmpty(tt, createdSchema) + assert.NotEmpty(tt, licenseApplicationSchema) + + // create a second schema for the creds to be issued after the application is approved + licenseSchema, err := schemaService.CreateSchema( + context.Background(), + schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: getLicenseSchema(), Sign: true}) + assert.NoError(tt, err) + assert.NotEmpty(tt, licenseSchema) // issue a credential against the schema to the subject, from the issuer createdCred, err := credentialService.CreateCredential( @@ -420,9 +382,9 @@ func TestManifestAPI(t *testing.T) { Issuer: issuerDID.DID.ID, IssuerKID: kid, Subject: applicantDID.ID, - SchemaID: createdSchema.ID, + SchemaID: licenseApplicationSchema.ID, Data: map[string]any{ - "licenseType": "WA-DL-CLASS-A", + "licenseType": "Class D", "firstName": "Tester", "lastName": "McTest", }, @@ -430,9 +392,8 @@ func TestManifestAPI(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, createdCred) - // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) - + // create a manifest with the schema we'll be issuing against after reviewing applications + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, licenseSchema.ID) requestValue := newRequestValue(tt, createManifestRequest) req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) w := httptest.NewRecorder() @@ -464,7 +425,7 @@ func TestManifestAPI(t *testing.T) { mockClock.Set(expiryDateTime) expiryDuration := 5 * time.Second issuanceTemplate, err := issuanceService.CreateIssuanceTemplate(context.Background(), - getValidIssuanceTemplateRequest(m, issuerDID, createdSchema, expiryDateTime, expiryDuration)) + getValidIssuanceTemplateRequest(m, issuerDID, licenseSchema.ID, expiryDateTime, expiryDuration)) assert.NoError(tt, err) assert.NotEmpty(tt, issuanceTemplate) @@ -496,13 +457,16 @@ func TestManifestAPI(t *testing.T) { } assert.Equal(tt, expectedSubject, vc.CredentialSubject) assert.Equal(tt, time.Date(2022, 10, 31, 0, 0, 0, 0, time.UTC).Format(time.RFC3339), vc.ExpirationDate) - assert.Equal(tt, createdSchema.ID, vc.CredentialSchema.ID) + assert.Equal(tt, licenseSchema.ID, vc.CredentialSchema.ID) assert.Empty(tt, vc.CredentialStatus) _, _, vc2, err := credsdk.ToCredential(appResp.Credentials[1]) assert.NoError(tt, err) expectedSubject = credsdk.CredentialSubject{ - "id": applicantDID.ID, + "id": applicantDID.ID, + "firstName": "Tester", + "lastName": "McTest", + "state": "NY", "someCrazyObject": map[string]any{ "foo": 123., "bar": false, @@ -516,11 +480,11 @@ func TestManifestAPI(t *testing.T) { time.Date(2022, 10, 31, 0, 0, 5, 0, time.UTC).Format(time.RFC3339), vc2.ExpirationDate, ) - assert.Equal(tt, createdSchema.ID, vc2.CredentialSchema.ID) + assert.Equal(tt, licenseSchema.ID, vc2.CredentialSchema.ID) assert.NotEmpty(tt, vc2.CredentialStatus) }) - t.Run("Test Submit Application", func(tt *testing.T) { + t.Run("Test Submit Application with multiple outputs and overrides", func(tt *testing.T) { bolt := setupTestDB(tt) require.NotEmpty(tt, bolt) @@ -558,38 +522,35 @@ func TestManifestAPI(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, applicantDID) - // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } + // create a schema for the creds to be issued against, needed for the application kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema(context.Background(), - schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + licenseApplicationSchema, err := schemaService.CreateSchema( + context.Background(), + schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license application schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) - assert.NotEmpty(tt, createdSchema) + assert.NotEmpty(tt, licenseApplicationSchema) + + // create a second schema for the creds to be issued after the application is approved + licenseSchema, err := schemaService.CreateSchema( + context.Background(), + schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: getLicenseSchema(), Sign: true}) + assert.NoError(tt, err) + assert.NotEmpty(tt, licenseSchema) // issue a credential against the schema to the subject, from the issuer createdCred, err := credentialService.CreateCredential(context.Background(), credential.CreateCredentialRequest{ Issuer: issuerDID.DID.ID, IssuerKID: kid, Subject: applicantDID.ID, - SchemaID: createdSchema.ID, - Data: map[string]any{"licenseType": "WA-DL-CLASS-A"}, + SchemaID: licenseApplicationSchema.ID, + Data: map[string]any{"licenseType": "Class D"}, }) assert.NoError(tt, err) assert.NotEmpty(tt, createdCred) - // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) - + // good request to create a manifest + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, licenseSchema.ID) w = httptest.NewRecorder() - requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) c = newRequestContext(w, req) @@ -635,8 +596,23 @@ func TestManifestAPI(t *testing.T) { Approved: true, Reason: "I'm the almighty approver", CredentialOverrides: map[string]manifestsvc.CredentialOverride{ - "id1": { - Data: map[string]any{"looks": "pretty darn handsome"}, + "drivers-license-ca": { + Data: map[string]any{ + "firstName": "John", + "lastName": "Doe", + "state": "CA", + "looks": "pretty darn handsome", + }, + Expiry: &expireAt, + Revocable: true, + }, + "drivers-license-ny": { + Data: map[string]any{ + "firstName": "John", + "lastName": "Doe", + "state": "NY", + "looks": "even handsomer", + }, Expiry: &expireAt, Revocable: true, }, @@ -662,12 +638,15 @@ func TestManifestAPI(t *testing.T) { _, _, vc, err := credsdk.ToCredential(appResp.Credentials[0]) assert.NoError(tt, err) assert.Equal(tt, credsdk.CredentialSubject{ - "id": applicantDID.ID, - "looks": "pretty darn handsome", + "id": applicantDID.ID, + "firstName": "John", + "lastName": "Doe", + "state": "CA", + "looks": "pretty darn handsome", }, vc.CredentialSubject) assert.Equal(tt, expireAt.Format(time.RFC3339), vc.ExpirationDate) assert.NotEmpty(tt, vc.CredentialStatus) - assert.Equal(tt, createdSchema.ID, vc.CredentialSchema.ID) + assert.Equal(tt, licenseSchema.ID, vc.CredentialSchema.ID) }) t.Run("Test Denied Application", func(tt *testing.T) { @@ -712,28 +691,19 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, applicantDID) // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema(context.Background(), - schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + licenseApplicationSchema, err := schemaService.CreateSchema(context.Background(), + schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license application schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) - assert.NotEmpty(tt, createdSchema) + assert.NotEmpty(tt, licenseApplicationSchema) // issue a credential against the schema to the subject, from the issuer createdCred, err := credentialService.CreateCredential(context.Background(), credential.CreateCredentialRequest{ Issuer: issuerDID.DID.ID, IssuerKID: kid, Subject: applicantDID.ID, - SchemaID: createdSchema.ID, - Data: map[string]any{"licenseType": "WA-DL-CLASS-A"}, + SchemaID: licenseApplicationSchema.ID, + Data: map[string]any{"licenseType": "Class D"}, }) assert.NoError(tt, err) assert.NotEmpty(tt, createdCred) @@ -741,7 +711,7 @@ func TestManifestAPI(t *testing.T) { w = httptest.NewRecorder() // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, licenseApplicationSchema.ID) requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) @@ -823,9 +793,9 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, appResp.Response) assert.Equal(tt, resp.Manifest.ID, appResp.Response.ManifestID) assert.NotEmpty(tt, appResp.Response.Denial) - assert.Contains(tt, appResp.Response.Denial.Reason, "unfilled input descriptor(s): test-id: no submission descriptor found for input descriptor") + assert.Contains(tt, appResp.Response.Denial.Reason, "unfilled input descriptor(s): license-type: no submission descriptor found for input descriptor") assert.Len(tt, appResp.Response.Denial.InputDescriptors, 1) - assert.Equal(tt, appResp.Response.Denial.InputDescriptors[0], "test-id") + assert.Equal(tt, appResp.Response.Denial.InputDescriptors[0], "license-type") }) t.Run("Test Get Application By ID and Get Applications", func(tt *testing.T) { @@ -867,34 +837,30 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, applicantDID) // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } kid := issuerDID.DID.VerificationMethod[0].ID - createdSchema, err := schemaService.CreateSchema(context.Background(), - schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + licenseApplicationSchema, err := schemaService.CreateSchema(context.Background(), + schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license application schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) - assert.NotEmpty(tt, createdSchema) + assert.NotEmpty(tt, licenseApplicationSchema) + licenseSchema, err := schemaService.CreateSchema( + context.Background(), + schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: getLicenseSchema(), Sign: true}) + assert.NoError(tt, err) + assert.NotEmpty(tt, licenseSchema) // issue a credential against the schema to the subject, from the issuer createdCred, err := credentialService.CreateCredential(context.Background(), credential.CreateCredentialRequest{ Issuer: issuerDID.DID.ID, IssuerKID: kid, Subject: applicantDID.ID, - SchemaID: createdSchema.ID, - Data: map[string]any{"licenseType": "WA-DL-CLASS-A"}, + SchemaID: licenseApplicationSchema.ID, + Data: map[string]any{"licenseType": "Class D"}, }) assert.NoError(tt, err) assert.NotEmpty(tt, createdCred) // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, licenseSchema.ID) requestValue := newRequestValue(tt, createManifestRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) @@ -931,7 +897,28 @@ func TestManifestAPI(t *testing.T) { assert.NoError(tt, err) // review application - reviewApplicationRequestValue := newRequestValue(tt, router.ReviewApplicationRequest{Approved: true, Reason: "I'm the almighty approver"}) + reviewApplicationRequestValue := newRequestValue(tt, router.ReviewApplicationRequest{ + Approved: true, + Reason: "I'm the almighty approver", + CredentialOverrides: map[string]manifestsvc.CredentialOverride{ + "drivers-license-ca": { + Data: map[string]any{ + "firstName": "John", + "lastName": "Doe", + "state": "CA", + "looks": "pretty darn handsome", + }, + }, + "drivers-license-ny": { + Data: map[string]any{ + "firstName": "John", + "lastName": "Doe", + "state": "NY", + "looks": "even handsomer", + }, + }, + }, + }) applicationID := storage.StatusObjectID(op.ID) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests/applications/"+applicationID+"/review", reviewApplicationRequestValue) c = newRequestContextWithParams(w, req, map[string]string{"id": applicationID}) @@ -1027,18 +1014,9 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, applicantDID) // create a schema for the creds to be issued against - licenseSchema := map[string]any{ - "type": "object", - "properties": map[string]any{ - "licenseType": map[string]any{ - "type": "string", - }, - }, - "additionalProperties": true, - } kid := issuerDID.DID.VerificationMethod[0].ID createdSchema, err := schemaService.CreateSchema(context.Background(), - schema.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "license schema", Schema: licenseSchema, Sign: true}) + schema.CreateSchemaRequest{Issuer: issuerDID.DID.ID, IssuerKID: kid, Name: "license schema", Schema: getLicenseApplicationSchema(), Sign: true}) assert.NoError(tt, err) assert.NotEmpty(tt, createdSchema) @@ -1054,7 +1032,7 @@ func TestManifestAPI(t *testing.T) { assert.NotEmpty(tt, createdCred) // good request - createManifestRequest := getValidManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) + createManifestRequest := getValidCreateManifestRequest(issuerDID.DID.ID, issuerDID.DID.VerificationMethod[0].ID, createdSchema.ID) requestValue := newRequestValue(tt, createManifestRequest) req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/manifests", requestValue) @@ -1133,17 +1111,16 @@ func TestManifestAPI(t *testing.T) { func getValidManifestRequestRequest(issuerDID *did.CreateDIDResponse, kid string, credentialManifest manifest.CredentialManifest) router.CreateManifestRequestRequest { return router.CreateManifestRequestRequest{ CommonCreateRequestRequest: &router.CommonCreateRequestRequest{ - Audience: []string{"mario"}, - IssuerDID: issuerDID.DID.ID, - IssuerKID: kid, - Expiration: "", + Audience: []string{"mario"}, + IssuerDID: issuerDID.DID.ID, + IssuerKID: kid, }, CredentialManifestID: credentialManifest.ID, } } func getValidIssuanceTemplateRequest(m manifest.CredentialManifest, issuerDID *did.CreateDIDResponse, - createdSchema *schema.CreateSchemaResponse, expiry1 time.Time, expiry2 time.Duration) *issuance.CreateIssuanceTemplateRequest { + schemaID string, expiry1 time.Time, expiry2 time.Duration) *issuance.CreateIssuanceTemplateRequest { return &issuance.CreateIssuanceTemplateRequest{ IssuanceTemplate: issuance.Template{ ID: uuid.NewString(), @@ -1152,9 +1129,9 @@ func getValidIssuanceTemplateRequest(m manifest.CredentialManifest, issuerDID *d IssuerKID: issuerDID.DID.VerificationMethod[0].ID, Credentials: []issuance.CredentialTemplate{ { - ID: "id1", - Schema: createdSchema.ID, - CredentialInputDescriptor: "test-id", + ID: "drivers-license-ca", + Schema: schemaID, + CredentialInputDescriptor: "license-type", Data: issuance.ClaimTemplates{ "firstName": "$.credentialSubject.firstName", "lastName": "$.credentialSubject.lastName", @@ -1165,10 +1142,13 @@ func getValidIssuanceTemplateRequest(m manifest.CredentialManifest, issuerDID *d }, }, { - ID: "id2", - Schema: createdSchema.ID, - CredentialInputDescriptor: "test-id", + ID: "drivers-license-ny", + Schema: schemaID, + CredentialInputDescriptor: "license-type", Data: issuance.ClaimTemplates{ + "firstName": "$.credentialSubject.firstName", + "lastName": "$.credentialSubject.lastName", + "state": "NY", "someCrazyObject": map[string]any{ "foo": 123, "bar": false, @@ -1184,3 +1164,45 @@ func getValidIssuanceTemplateRequest(m manifest.CredentialManifest, issuerDID *d }, } } + +func getLicenseApplicationSchema() map[string]any { + return map[string]any{ + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", + "properties": map[string]any{ + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "licenseType": map[string]any{ + "type": "string", + }, + }, + "required": []any{"licenseType"}, + }, + }, + } +} + +func getLicenseSchema() map[string]any { + return map[string]any{ + "$schema": "https://json-schema.org/draft-07/schema", + "type": "object", + "properties": map[string]any{ + "credentialSubject": map[string]any{ + "type": "object", + "properties": map[string]any{ + "firstName": map[string]any{ + "type": "string", + }, + "lastName": map[string]any{ + "type": "string", + }, + "state": map[string]any{ + "type": "string", + }, + }, + "required": []any{"firstName", "lastName", "state"}, + }, + }, + } +} diff --git a/pkg/server/server_schema_test.go b/pkg/server/server_schema_test.go index 288c0bf3f..b21ec3661 100644 --- a/pkg/server/server_schema_test.go +++ b/pkg/server/server_schema_test.go @@ -1,26 +1,22 @@ package server import ( - "context" "fmt" "net/http" "net/http/httptest" "testing" "github.com/TBD54566975/ssi-sdk/credential/schema" - "github.com/TBD54566975/ssi-sdk/crypto" - didsdk "github.com/TBD54566975/ssi-sdk/did" "github.com/goccy/go-json" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tbd54566975/ssi-service/internal/util" "github.com/tbd54566975/ssi-service/pkg/server/router" - "github.com/tbd54566975/ssi-service/pkg/service/did" ) func TestSchemaAPI(t *testing.T) { - t.Run("Test Create SchemaID", func(tt *testing.T) { + t.Run("Test Create Schema", func(tt *testing.T) { bolt := setupTestDB(tt) require.NotEmpty(tt, bolt) @@ -41,7 +37,7 @@ func TestSchemaAPI(t *testing.T) { // reset the http recorder w = httptest.NewRecorder() - schemaRequest := router.CreateSchemaRequest{Author: "did:test", Name: "test schema", Schema: simpleSchema} + schemaRequest := router.CreateSchemaRequest{Name: "test schema", Schema: simpleSchema} schemaRequestValue = newRequestValue(tt, schemaRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/schemas", schemaRequestValue) @@ -53,84 +49,13 @@ func TestSchemaAPI(t *testing.T) { err := json.NewDecoder(w.Body).Decode(&resp) assert.NoError(tt, err) assert.NotEmpty(tt, resp.ID) - assert.EqualValues(tt, schemaRequest.Schema, resp.Schema.Schema) - }) - - t.Run("Test Sign & Verify Schema", func(tt *testing.T) { - bolt := setupTestDB(tt) - require.NotEmpty(tt, bolt) - keyStoreService := testKeyStoreService(tt, bolt) - didService := testDIDService(tt, bolt, keyStoreService) - schemaService := testSchemaRouter(tt, bolt, keyStoreService, didService) - - w := httptest.NewRecorder() - - // sign request with unknown DID - simpleSchema := getTestSchema() - schemaRequest := router.CreateSchemaRequest{Author: "did:test", Name: "test schema", Schema: simpleSchema, Sign: true} - schemaRequestValue := newRequestValue(tt, schemaRequest) - req := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/schemas", schemaRequestValue) - c := newRequestContext(w, req) - schemaService.CreateSchema(c) - assert.Contains(tt, w.Body.String(), "cannot sign schema without authorKID") - - // create a DID - issuerDID, err := didService.CreateDIDByMethod(context.Background(), did.CreateDIDRequest{ - Method: didsdk.KeyMethod, - KeyType: crypto.Ed25519, - }) - assert.NoError(tt, err) - assert.NotEmpty(tt, issuerDID) - - // sign with known DID - kid := issuerDID.DID.VerificationMethod[0].ID - schemaRequest = router.CreateSchemaRequest{Author: issuerDID.DID.ID, AuthorKID: kid, Name: "test schema", Schema: simpleSchema, Sign: true} - schemaRequestValue = newRequestValue(tt, schemaRequest) - req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/schemas", schemaRequestValue) - w = httptest.NewRecorder() - c = newRequestContext(w, req) - schemaService.CreateSchema(c) - assert.True(tt, util.Is2xxResponse(w.Code)) - - var resp router.CreateSchemaResponse - err = json.NewDecoder(w.Body).Decode(&resp) - assert.NoError(tt, err) - assert.NotEmpty(tt, resp.SchemaJWT) - assert.NotEmpty(tt, resp.ID) - assert.EqualValues(tt, schemaRequest.Schema, resp.Schema.Schema) - - // verify schema - verifySchemaRequest := router.VerifySchemaRequest{SchemaJWT: *resp.SchemaJWT} - verifySchemaRequestValue := newRequestValue(tt, verifySchemaRequest) - req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/schemas/verification", verifySchemaRequestValue) - c = newRequestContext(w, req) - schemaService.VerifySchema(c) - assert.True(tt, util.Is2xxResponse(w.Code)) - - var verifyResp router.VerifySchemaResponse - err = json.NewDecoder(w.Body).Decode(&verifyResp) - assert.NoError(tt, err) - assert.NotEmpty(tt, verifyResp) - assert.True(tt, verifyResp.Verified) - - // verify a bad schema - verifySchemaRequest = router.VerifySchemaRequest{SchemaJWT: "bad"} - verifySchemaRequestValue = newRequestValue(tt, verifySchemaRequest) - req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/schemas/verification", verifySchemaRequestValue) - w = httptest.NewRecorder() - c = newRequestContext(w, req) - schemaService.VerifySchema(c) - assert.True(tt, util.Is2xxResponse(w.Code)) - - err = json.NewDecoder(w.Body).Decode(&verifyResp) - assert.NoError(tt, err) - assert.NotEmpty(tt, verifyResp) - assert.False(tt, verifyResp.Verified) - assert.Contains(tt, verifyResp.Reason, "could not verify schema") + // since the id is generated, we need to manually override it + schemaRequest.Schema[schema.JSONSchemaIDProperty] = resp.Schema.ID() + assert.JSONEq(tt, schemaRequest.Schema.String(), resp.Schema.String()) }) - t.Run("Test Get SchemaID and Get Schemas", func(tt *testing.T) { + t.Run("Test Get Schema and Get Schemas", func(tt *testing.T) { bolt := setupTestDB(tt) require.NotEmpty(tt, bolt) @@ -174,7 +99,7 @@ func TestSchemaAPI(t *testing.T) { // create a schema simpleSchema := getTestSchema() - schemaRequest := router.CreateSchemaRequest{Author: "did:test", Name: "test schema", Schema: simpleSchema} + schemaRequest := router.CreateSchemaRequest{Name: "test schema", Schema: simpleSchema} schemaRequestValue := newRequestValue(tt, schemaRequest) createReq := httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/schemas", schemaRequestValue) @@ -187,7 +112,10 @@ func TestSchemaAPI(t *testing.T) { assert.NoError(tt, err) assert.NotEmpty(tt, createResp.ID) - assert.EqualValues(tt, schemaRequest.Schema, createResp.Schema.Schema) + + // since the id is generated, we need to manually override it + schemaRequest.Schema[schema.JSONSchemaIDProperty] = createResp.Schema.ID() + assert.JSONEq(tt, schemaRequest.Schema.String(), createResp.Schema.String()) // reset recorder between calls w = httptest.NewRecorder() @@ -202,8 +130,8 @@ func TestSchemaAPI(t *testing.T) { err = json.NewDecoder(w.Body).Decode(&gotSchemaResp) assert.NoError(tt, err) - assert.Equal(tt, createResp.ID, gotSchemaResp.Schema.ID) - assert.Equal(tt, createResp.Schema.Schema, gotSchemaResp.Schema.Schema) + assert.Contains(tt, gotSchemaResp.Schema.ID(), createResp.ID) + assert.Equal(tt, createResp.Schema.Schema(), gotSchemaResp.Schema.Schema()) // reset recorder between calls w = httptest.NewRecorder() @@ -238,7 +166,7 @@ func TestSchemaAPI(t *testing.T) { // create a schema simpleSchema := getTestSchema() - schemaRequest := router.CreateSchemaRequest{Author: "did:test", Name: "test schema", Schema: simpleSchema} + schemaRequest := router.CreateSchemaRequest{Name: "test schema", Schema: simpleSchema} schemaRequestValue := newRequestValue(tt, schemaRequest) req = httptest.NewRequest(http.MethodPut, "https://ssi-service.com/v1/schemas", schemaRequestValue) w = httptest.NewRecorder() @@ -250,7 +178,10 @@ func TestSchemaAPI(t *testing.T) { err := json.NewDecoder(w.Body).Decode(&resp) assert.NoError(tt, err) assert.NotEmpty(tt, resp.ID) - assert.EqualValues(tt, schemaRequest.Schema, resp.Schema.Schema) + + // since the id is generated, we need to manually override it + schemaRequest.Schema[schema.JSONSchemaIDProperty] = resp.Schema.ID() + assert.JSONEq(tt, schemaRequest.Schema.String(), resp.Schema.String()) // get schema by id req = httptest.NewRequest(http.MethodGet, fmt.Sprintf("https://ssi-service.com/v1/schemas/%s", resp.ID), nil) @@ -278,8 +209,9 @@ func TestSchemaAPI(t *testing.T) { func getTestSchema() schema.JSONSchema { return map[string]any{ "$id": "https://example.com/foo.schema.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "description": "foo schema", + "$schema": "https://json-schema.org/draft-07/schema", + "name": "test schema", + "description": "test schema", "type": "object", "properties": map[string]any{ "foo": map[string]any{ diff --git a/pkg/server/server_test.go b/pkg/server/server_test.go index dedd20007..24146a455 100644 --- a/pkg/server/server_test.go +++ b/pkg/server/server_test.go @@ -129,7 +129,7 @@ func newRequestContextWithParams(w http.ResponseWriter, req *http.Request, param return c } -func getValidManifestRequest(issuerDID, issuerKID, schemaID string) model.CreateManifestRequest { +func getValidCreateManifestRequest(issuerDID, issuerKID, schemaID string) model.CreateManifestRequest { return model.CreateManifestRequest{ IssuerDID: issuerDID, IssuerKID: issuerKID, @@ -137,14 +137,18 @@ func getValidManifestRequest(issuerDID, issuerKID, schemaID string) model.Create JWTVC: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}}, }, PresentationDefinition: &exchange.PresentationDefinition{ - ID: "id123", + ID: "valid-license-application", InputDescriptors: []exchange.InputDescriptor{ { - ID: "test-id", + ID: "license-type", Constraints: &exchange.Constraints{ Fields: []exchange.Field{ { Path: []string{"$.vc.credentialSubject.licenseType"}, + Filter: &exchange.Filter{ + Type: "string", + Pattern: "Class D|Class M|Class V", + }, }, }, }, @@ -153,16 +157,16 @@ func getValidManifestRequest(issuerDID, issuerKID, schemaID string) model.Create }, OutputDescriptors: []manifestsdk.OutputDescriptor{ { - ID: "id1", + ID: "drivers-license-ca", Schema: schemaID, - Name: "good ID", - Description: "it's all good", + Name: "drivers license CA", + Description: "license for CA", }, { - ID: "id2", + ID: "drivers-license-ny", Schema: schemaID, - Name: "good ID", - Description: "it's all good", + Name: "drivers license NY", + Description: "license for NY", }, }, } @@ -177,7 +181,7 @@ func getValidApplicationRequest(manifestID, presDefID, submissionDescriptorID st JWTVC: &exchange.JWTType{Alg: []crypto.SignatureAlgorithm{crypto.EdDSA}}, }, PresentationSubmission: &exchange.PresentationSubmission{ - ID: "psid", + ID: "license-application-submission", DefinitionID: presDefID, DescriptorMap: []exchange.SubmissionDescriptor{ { diff --git a/pkg/service/credential/model.go b/pkg/service/credential/model.go index 3f326410d..0631f37e4 100644 --- a/pkg/service/credential/model.go +++ b/pkg/service/credential/model.go @@ -4,10 +4,6 @@ import ( "github.com/tbd54566975/ssi-service/internal/credential" ) -const ( - SchemaLDType string = "JsonSchemaValidator2018" -) - type CreateCredentialRequest struct { Issuer string `json:"issuer" validate:"required"` IssuerKID string `json:"issuerKid" validate:"required"` @@ -20,7 +16,7 @@ type CreateCredentialRequest struct { Expiry string `json:"expiry,omitempty"` Revocable bool `json:"revocable,omitempty"` Suspendable bool `json:"suspendable,omitempty"` - // TODO(gabe) support more capabilities like signature type, format, status, and more. + // TODO(gabe) support more capabilities like signature type, format, evidence, and more. } // CreateCredentialResponse holds a resulting credential from credential creation, which is an XOR type: diff --git a/pkg/service/credential/service.go b/pkg/service/credential/service.go index 504cc3b0b..bec4cd5f0 100644 --- a/pkg/service/credential/service.go +++ b/pkg/service/credential/service.go @@ -3,7 +3,6 @@ package credential import ( "context" "fmt" - "strconv" "time" "github.com/TBD54566975/ssi-sdk/credential" @@ -11,7 +10,6 @@ import ( statussdk "github.com/TBD54566975/ssi-sdk/credential/status" "github.com/TBD54566975/ssi-sdk/did/resolution" sdkutil "github.com/TBD54566975/ssi-sdk/util" - "github.com/google/uuid" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -91,10 +89,8 @@ func NewCredentialService(config config.CredentialServiceConfig, s storage.Servi func (s Service) CreateCredential(ctx context.Context, request CreateCredentialRequest) (*CreateCredentialResponse, error) { watchKeys := make([]storage.WatchKey, 0) - var slcMetadata StatusListCredentialMetadata - + var statusMetadata StatusListCredentialMetadata if request.hasStatus() && request.isStatusValid() { - statusPurpose := statussdk.StatusRevocation if request.Suspendable { @@ -109,11 +105,10 @@ func (s Service) CreateCredential(ctx context.Context, request CreateCredentialR watchKeys = append(watchKeys, statusListCredentialIndexPoolWatchKey) watchKeys = append(watchKeys, statusListCredentialCurrentIndexWatchKey) - slcMetadata = StatusListCredentialMetadata{statusListCredentialWatchKey: statusListCredentialWatchKey, statusListIndexPoolWatchKey: statusListCredentialIndexPoolWatchKey, statusListCurrentIndexWatchKey: statusListCredentialCurrentIndexWatchKey} + statusMetadata = StatusListCredentialMetadata{statusListCredentialWatchKey: statusListCredentialWatchKey, statusListIndexPoolWatchKey: statusListCredentialIndexPoolWatchKey, statusListCurrentIndexWatchKey: statusListCredentialCurrentIndexWatchKey} } - returnFunc := s.createCredentialFunc(request, slcMetadata) - + returnFunc := s.createCredentialFunc(request, statusMetadata) returnValue, err := s.storage.db.Execute(ctx, returnFunc, watchKeys) if err != nil { return nil, errors.Wrap(err, "execute") @@ -121,7 +116,7 @@ func (s Service) CreateCredential(ctx context.Context, request CreateCredentialR credResponse, ok := returnValue.(*CreateCredentialResponse) if !ok { - return nil, errors.New("Problem with casting to CreateCredentialResponse") + return nil, errors.New("problem casting to CreateCredentialResponse") } return credResponse, nil @@ -129,11 +124,11 @@ func (s Service) CreateCredential(ctx context.Context, request CreateCredentialR func (s Service) createCredentialFunc(request CreateCredentialRequest, slcMetadata StatusListCredentialMetadata) storage.BusinessLogicFunc { return func(ctx context.Context, tx storage.Tx) (any, error) { - return s.createCredentialBusinessLogic(ctx, request, tx, slcMetadata) + return s.createCredential(ctx, request, tx, slcMetadata) } } -func (s Service) createCredentialBusinessLogic(ctx context.Context, request CreateCredentialRequest, tx storage.Tx, slcMetadata StatusListCredentialMetadata) (*CreateCredentialResponse, error) { +func (s Service) createCredential(ctx context.Context, request CreateCredentialRequest, tx storage.Tx, statusMetadata StatusListCredentialMetadata) (*CreateCredentialResponse, error) { logrus.Debugf("creating credential: %+v", request) if !request.isStatusValid() { @@ -141,7 +136,6 @@ func (s Service) createCredentialBusinessLogic(ctx context.Context, request Crea } builder := credential.NewVerifiableCredentialBuilder() - if err := builder.SetIssuer(request.Issuer); err != nil { return nil, sdkutil.LoggingErrorMsgf(err, "could not build credential when setting issuer: %s", request.Issuer) } @@ -154,7 +148,6 @@ func (s Service) createCredentialBusinessLogic(ctx context.Context, request Crea // set subject value subject := credential.CredentialSubject(request.Data) subject[credential.VerifiableCredentialIDProperty] = request.Subject - if err := builder.SetCredentialSubject(subject); err != nil { return nil, sdkutil.LoggingErrorMsgf(err, "could not set subject: %+v", subject) } @@ -167,7 +160,7 @@ func (s Service) createCredentialBusinessLogic(ctx context.Context, request Crea } // if a schema value exists, verify we can access it, validate the data against it, then set it - var knownSchema *schemalib.VCJSONSchema + var knownSchema *schemalib.JSONSchema if request.SchemaID != "" { // resolve schema and save it for validation later gotSchema, err := s.schema.GetSchema(ctx, schema.GetSchemaRequest{ID: request.SchemaID}) @@ -175,13 +168,12 @@ func (s Service) createCredentialBusinessLogic(ctx context.Context, request Crea return nil, sdkutil.LoggingErrorMsgf(err, "failed to create credential; could not get schema: %s", request.SchemaID) } knownSchema = &gotSchema.Schema - credSchema := credential.CredentialSchema{ ID: request.SchemaID, - Type: SchemaLDType, + Type: schemalib.JSONSchema2023Type.String(), } if err = builder.SetCredentialSchema(credSchema); err != nil { - return nil, sdkutil.LoggingErrorMsgf(err, "could not set JSON SchemaID for credential: %s", request.SchemaID) + return nil, sdkutil.LoggingErrorMsgf(err, "could not set JSON Schema for credential: %s", request.SchemaID) } } @@ -193,67 +185,15 @@ func (s Service) createCredentialBusinessLogic(ctx context.Context, request Crea } if err := builder.SetIssuanceDate(time.Now().Format(time.RFC3339)); err != nil { - errMsg := fmt.Sprintf("could not set credential issuance date") - return nil, sdkutil.LoggingErrorMsg(err, errMsg) + return nil, sdkutil.LoggingErrorMsg(err, "could not set credential issuance date") } if request.hasStatus() { - credID := builder.ID - issuerID := request.Issuer - issuerKID := request.IssuerKID - schemaID := request.SchemaID - - statusPurpose := statussdk.StatusRevocation - - if request.Suspendable { - statusPurpose = statussdk.StatusSuspension - } - - var slCredential *credential.VerifiableCredential - var statusListCredentialID string - var randomIndex int - var err error - - statusListCredential, err := s.storage.GetStatusListCredentialKeyData( - ctx, - issuerID, - schemaID, - statusPurpose, - ) + statusEntry, err := s.createStatusListEntryForCredential(ctx, builder.ID, request, tx, statusMetadata) if err != nil { - return nil, errors.Wrap(err, "getting status list credential key data") - } - - if statusListCredential == nil { - // creates status list credential with random index - randomIndex, slCredential, err = createStatusListCredential(ctx, tx, s, statusPurpose, issuerID, issuerKID, schemaID, slcMetadata) - if err != nil { - return nil, sdkutil.LoggingErrorMsgf(err, "problem with getting status list credential") - } - - statusListCredentialID = slCredential.ID - } else { - randomIndex, err = s.storage.GetNextStatusListRandomIndex(ctx, slcMetadata) - if err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "problem with getting status list index") - } - - statusListCredentialID = statusListCredential.Credential.ID - - if err := s.storage.IncrementStatusListIndexTx(ctx, tx, slcMetadata); err != nil { - return nil, errors.Wrap(err, "incrementing status list index") - } + return nil, sdkutil.LoggingErrorMsg(err, "could not create status list entry for credential") } - - status := statussdk.StatusList2021Entry{ - ID: fmt.Sprintf(`%s/v1/credentials/%s/status`, s.config.ServiceEndpoint, credID), - Type: statussdk.StatusList2021EntryType, - StatusPurpose: statusPurpose, - StatusListIndex: strconv.Itoa(randomIndex), - StatusListCredential: statusListCredentialID, - } - - if err := builder.SetCredentialStatus(status); err != nil { + if err = builder.SetCredentialStatus(statusEntry); err != nil { return nil, sdkutil.LoggingErrorMsg(err, "could not set credential status") } } @@ -265,7 +205,7 @@ func (s Service) createCredentialBusinessLogic(ctx context.Context, request Crea // verify the built schema complies with the schema we've set if knownSchema != nil { - if err = schemalib.IsCredentialValidForVCJSONSchema(*cred, *knownSchema); err != nil { + if err = schemalib.IsCredentialValidForJSONSchema(*cred, *knownSchema); err != nil { return nil, sdkutil.LoggingErrorMsgf(err, "credential data does not comply with the provided schema: %s", request.SchemaID) } } @@ -289,56 +229,12 @@ func (s Service) createCredentialBusinessLogic(ctx context.Context, request Crea Suspended: false, } - credentialStorageRequest := StoreCredentialRequest{ - Container: container, - } - + credentialStorageRequest := StoreCredentialRequest{Container: container} if err = s.storage.StoreCredentialTx(ctx, tx, credentialStorageRequest); err != nil { return nil, sdkutil.LoggingErrorMsg(err, "saving credential") } - response := CreateCredentialResponse{Container: container} - return &response, nil -} - -func createStatusListCredential(ctx context.Context, tx storage.Tx, s Service, statusPurpose statussdk.StatusPurpose, issuerID, issuerKID, schemaID string, slcMetadata StatusListCredentialMetadata) (int, *credential.VerifiableCredential, error) { - statusListID := fmt.Sprintf("%s/v1/credentials/status/%s", s.config.ServiceEndpoint, uuid.NewString()) - - generatedStatusListCredential, err := statussdk.GenerateStatusList2021Credential(statusListID, issuerID, statusPurpose, []credential.VerifiableCredential{}) - if err != nil { - return -1, nil, sdkutil.LoggingErrorMsg(err, "could not generate status list") - } - - if schemaID != "" { - credSchema := credential.CredentialSchema{ - ID: schemaID, - Type: SchemaLDType, - } - generatedStatusListCredential.CredentialSchema = &credSchema - } - - statusListCredJWT, err := s.signCredentialJWT(ctx, issuerKID, *generatedStatusListCredential) - if err != nil { - return -1, nil, sdkutil.LoggingErrorMsg(err, "could not sign status list credential") - } - - statusListContainer := credint.Container{ - ID: generatedStatusListCredential.ID, - IssuerKID: issuerKID, - Credential: generatedStatusListCredential, - CredentialJWT: statusListCredJWT, - } - - statusListStorageRequest := StoreCredentialRequest{ - Container: statusListContainer, - } - - randomIndex, err := s.storage.CreateStatusListCredentialTx(ctx, tx, statusListStorageRequest, slcMetadata) - if err != nil { - return -1, nil, errors.Wrap(err, "creating status list credential") - } - - return randomIndex, generatedStatusListCredential, nil + return &CreateCredentialResponse{Container: container}, nil } // signCredentialJWT signs a credential and returns it as a vc-jwt diff --git a/pkg/service/credential/status.go b/pkg/service/credential/status.go new file mode 100644 index 000000000..c966d8e6a --- /dev/null +++ b/pkg/service/credential/status.go @@ -0,0 +1,97 @@ +package credential + +import ( + "context" + "fmt" + "strconv" + + "github.com/TBD54566975/ssi-sdk/credential" + statussdk "github.com/TBD54566975/ssi-sdk/credential/status" + sdkutil "github.com/TBD54566975/ssi-sdk/util" + "github.com/google/uuid" + "github.com/pkg/errors" + + credint "github.com/tbd54566975/ssi-service/internal/credential" + "github.com/tbd54566975/ssi-service/pkg/storage" +) + +func (s Service) createStatusListEntryForCredential(ctx context.Context, credID string, request CreateCredentialRequest, + tx storage.Tx, statusMetadata StatusListCredentialMetadata) (*statussdk.StatusList2021Entry, error) { + issuerID := request.Issuer + issuerKID := request.IssuerKID + schemaID := request.SchemaID + + statusPurpose := statussdk.StatusRevocation + if request.Suspendable { + statusPurpose = statussdk.StatusSuspension + } + + var statusCred *credential.VerifiableCredential + var statusListCredentialID string + var randomIndex int + var err error + statusListCredential, err := s.storage.GetStatusListCredentialKeyData(ctx, issuerID, schemaID, statusPurpose) + if err != nil { + return nil, errors.Wrap(err, "getting status list credential key data") + } + + if statusListCredential == nil { + // creates status list credential with random index + randomIndex, statusCred, err = s.createStatusListCredential(ctx, tx, statusPurpose, issuerID, issuerKID, statusMetadata) + if err != nil { + return nil, sdkutil.LoggingErrorMsgf(err, "problem with getting status list credential") + } + + statusListCredentialID = statusCred.ID + } else { + randomIndex, err = s.storage.GetNextStatusListRandomIndex(ctx, statusMetadata) + if err != nil { + return nil, sdkutil.LoggingErrorMsg(err, "problem with getting status list index") + } + + statusListCredentialID = statusListCredential.Credential.ID + if err = s.storage.IncrementStatusListIndexTx(ctx, tx, statusMetadata); err != nil { + return nil, errors.Wrap(err, "incrementing status list index") + } + } + + return &statussdk.StatusList2021Entry{ + ID: fmt.Sprintf(`%s/%s/status`, s.config.ServiceEndpoint, credID), + Type: statussdk.StatusList2021EntryType, + StatusPurpose: statusPurpose, + StatusListIndex: strconv.Itoa(randomIndex), + StatusListCredential: statusListCredentialID, + }, nil +} + +func (s Service) createStatusListCredential(ctx context.Context, tx storage.Tx, statusPurpose statussdk.StatusPurpose, issuerID, issuerKID string, slcMetadata StatusListCredentialMetadata) (int, *credential.VerifiableCredential, error) { + statusListID := fmt.Sprintf("%s/status/%s", s.config.ServiceEndpoint, uuid.NewString()) + + generatedStatusListCredential, err := statussdk.GenerateStatusList2021Credential(statusListID, issuerID, statusPurpose, []credential.VerifiableCredential{}) + if err != nil { + return -1, nil, sdkutil.LoggingErrorMsg(err, "could not generate status list") + } + + statusListCredJWT, err := s.signCredentialJWT(ctx, issuerKID, *generatedStatusListCredential) + if err != nil { + return -1, nil, sdkutil.LoggingErrorMsg(err, "could not sign status list credential") + } + + statusListContainer := credint.Container{ + ID: generatedStatusListCredential.ID, + IssuerKID: issuerKID, + Credential: generatedStatusListCredential, + CredentialJWT: statusListCredJWT, + } + + statusListStorageRequest := StoreCredentialRequest{ + Container: statusListContainer, + } + + randomIndex, err := s.storage.CreateStatusListCredentialTx(ctx, tx, statusListStorageRequest, slcMetadata) + if err != nil { + return -1, nil, errors.Wrap(err, "creating status list credential") + } + + return randomIndex, generatedStatusListCredential, nil +} diff --git a/pkg/service/credential/storage.go b/pkg/service/credential/storage.go index 142c291c9..ac66e0320 100644 --- a/pkg/service/credential/storage.go +++ b/pkg/service/credential/storage.go @@ -89,7 +89,7 @@ type StatusListIndex struct { func NewCredentialStorage(db storage.ServiceStorage) (*Storage, error) { if db == nil { - return nil, sdkutil.LoggingNewError("bolt db reference is nil") + return nil, sdkutil.LoggingNewError("db reference is nil") } return &Storage{db: db}, nil diff --git a/pkg/service/did/handler.go b/pkg/service/did/handler.go index f7e7ef149..753d611ee 100644 --- a/pkg/service/did/handler.go +++ b/pkg/service/did/handler.go @@ -49,7 +49,7 @@ type handlerResolver struct { method didsdk.Method } -func (h handlerResolver) Resolve(ctx context.Context, did string, _ ...resolution.ResolutionOption) (*resolution.ResolutionResult, error) { +func (h handlerResolver) Resolve(ctx context.Context, did string, _ ...resolution.Option) (*resolution.Result, error) { method, err := resolution.GetMethodForDID(did) if err != nil { return nil, errors.Wrap(err, "getting method from DID") @@ -66,7 +66,7 @@ func (h handlerResolver) Resolve(ctx context.Context, did string, _ ...resolutio if err != nil { return nil, errors.Wrap(err, "getting DID from handler") } - return &resolution.ResolutionResult{Document: gotDIDResponse.DID}, nil + return &resolution.Result{Document: gotDIDResponse.DID}, nil } func (h handlerResolver) Methods() []didsdk.Method { diff --git a/pkg/service/did/ion.go b/pkg/service/did/ion.go index 8ac4c36e4..985fc0402 100644 --- a/pkg/service/did/ion.go +++ b/pkg/service/did/ion.go @@ -53,7 +53,7 @@ type CreateIONDIDOptions struct { // Related: // - https://github.com/TBD54566975/ssi-sdk/issues/336 // - https://github.com/TBD54566975/ssi-sdk/issues/335 - ServiceEndpoints []ion.Service `json:"serviceEndpoints"` + ServiceEndpoints []did.Service `json:"serviceEndpoints"` } func (c CreateIONDIDOptions) Method() did.Method { @@ -131,7 +131,7 @@ func (h *ionHandler) CreateDID(ctx context.Context, request CreateDIDRequest) (* } // construct first document state - ldKeyType, err := did.KeyTypeToLDKeyType(request.KeyType) + ldKeyType, err := did.KeyTypeToMultikeyLDType(request.KeyType) if err != nil { return nil, errors.Wrap(err, "converting key type to LD key type") } diff --git a/pkg/service/did/model.go b/pkg/service/did/model.go index 1e0a28506..9b03a319d 100644 --- a/pkg/service/did/model.go +++ b/pkg/service/did/model.go @@ -17,9 +17,9 @@ type ResolveDIDRequest struct { } type ResolveDIDResponse struct { - ResolutionMetadata *resolution.ResolutionMetadata `json:"didResolutionMetadata,omitempty"` - DIDDocument *didsdk.Document `json:"didDocument"` - DIDDocumentMetadata *resolution.DocumentMetadata `json:"didDocumentMetadata,omitempty"` + ResolutionMetadata *resolution.Metadata `json:"didResolutionMetadata,omitempty"` + DIDDocument *didsdk.Document `json:"didDocument"` + DIDDocumentMetadata *resolution.DocumentMetadata `json:"didDocumentMetadata,omitempty"` } type CreateDIDRequestOptions interface { diff --git a/pkg/service/did/resolution/resolver.go b/pkg/service/did/resolution/resolver.go index e62eedd9d..f367e2de7 100644 --- a/pkg/service/did/resolution/resolver.go +++ b/pkg/service/did/resolution/resolver.go @@ -58,7 +58,7 @@ func NewServiceResolver(handlerResolver resolution.Resolver, localResolutionMeth // 2. Try to resolve with the local resolver // 3. Try to resolve with the universal resolver // TODO(gabe) avoid caching DIDs that should be externally resolved https://github.com/TBD54566975/ssi-service/issues/361 -func (sr *ServiceResolver) Resolve(ctx context.Context, did string, opts ...resolution.ResolutionOption) (*resolution.ResolutionResult, error) { +func (sr *ServiceResolver) Resolve(ctx context.Context, did string, opts ...resolution.Option) (*resolution.Result, error) { // check the did is valid if _, err := utilint.GetMethodForDID(did); err != nil { return nil, errors.Wrap(err, "getting method DID") diff --git a/pkg/service/did/resolution/universal.go b/pkg/service/did/resolution/universal.go index 02026a29f..d2fb73057 100644 --- a/pkg/service/did/resolution/universal.go +++ b/pkg/service/did/resolution/universal.go @@ -35,7 +35,7 @@ func newUniversalResolver(url string) (*universalResolver, error) { } // Resolve results resolution results by doing a GET on <url>/1.0.identifiers/<did>. -func (ur *universalResolver) Resolve(ctx context.Context, did string, _ ...resolution.ResolutionOption) (*resolution.ResolutionResult, error) { +func (ur *universalResolver) Resolve(ctx context.Context, did string, _ ...resolution.Option) (*resolution.Result, error) { url := ur.url + "/1.0/identifiers/" + did req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { @@ -51,7 +51,7 @@ func (ur *universalResolver) Resolve(ctx context.Context, did string, _ ...resol if err != nil { return nil, err } - var result resolution.ResolutionResult + var result resolution.Result if err = json.Unmarshal(respBody, &result); err != nil { return nil, errors.Wrap(err, "unmarshalling JSON") } diff --git a/pkg/service/did/service.go b/pkg/service/did/service.go index 2bd78f191..8e13efa6e 100644 --- a/pkg/service/did/service.go +++ b/pkg/service/did/service.go @@ -142,13 +142,13 @@ func (s *Service) ResolveDID(request ResolveDIDRequest) (*ResolveDIDResponse, er return nil, err } return &ResolveDIDResponse{ - ResolutionMetadata: &resolved.ResolutionMetadata, + ResolutionMetadata: &resolved.Metadata, DIDDocument: &resolved.Document, DIDDocumentMetadata: &resolved.DocumentMetadata, }, nil } -func (s *Service) Resolve(ctx context.Context, did string, opts ...didresolution.ResolutionOption) (*didresolution.ResolutionResult, error) { +func (s *Service) Resolve(ctx context.Context, did string, opts ...didresolution.Option) (*didresolution.Result, error) { return s.resolver.Resolve(ctx, did, opts) } diff --git a/pkg/service/did/storage.go b/pkg/service/did/storage.go index 9c812f56b..9501482e0 100644 --- a/pkg/service/did/storage.go +++ b/pkg/service/did/storage.go @@ -63,7 +63,7 @@ type Storage struct { func NewDIDStorage(db storage.ServiceStorage) (*Storage, error) { if db == nil { - return nil, errors.New("bolt db reference is nil") + return nil, errors.New("db reference is nil") } return &Storage{db: db}, nil } diff --git a/pkg/service/manifest/response.go b/pkg/service/manifest/response.go index ace209d3c..7d04d78b7 100644 --- a/pkg/service/manifest/response.go +++ b/pkg/service/manifest/response.go @@ -111,14 +111,23 @@ func (s Service) fulfillmentCredentialResponse(ctx context.Context, responseBuil // apply issuance template and then overrides if len(templateMap) != 0 { - templatedCredentialRequest, err := s.applyIssuanceTemplate(createCredentialRequest, templateMap, od, applicationJSON, credManifest, *application.PresentationSubmission) + template, ok := templateMap[od.ID] + if !ok { + logrus.Warnf("Did not find output_descriptor with ID \"%s\" in template. Skipping application.", od.ID) + continue + } + templatedCredentialRequest, err := s.applyIssuanceTemplate(createCredentialRequest, template, applicationJSON, credManifest, *application.PresentationSubmission) if err != nil { return nil, nil, err } createCredentialRequest = *templatedCredentialRequest } if len(credentialOverrides) != 0 { - createCredentialRequest = s.applyCredentialOverrides(createCredentialRequest, credentialOverrides, od) + if credentialOverride, ok := credentialOverrides[od.ID]; ok { + createCredentialRequest = s.applyCredentialOverrides(createCredentialRequest, credentialOverride) + } else { + logrus.Warnf("Did not find output_descriptor with ID \"%s\" in overrides. Skipping overrides.", od.ID) + } } credentialResponse, err := s.credential.CreateCredential(ctx, createCredentialRequest) @@ -156,23 +165,17 @@ func (s Service) fulfillmentCredentialResponse(ctx context.Context, responseBuil return credRes, creds, nil } -func (s Service) applyIssuanceTemplate(credentialRequest credential.CreateCredentialRequest, - templateMap map[string]issuance.CredentialTemplate, od manifest.OutputDescriptor, +func (s Service) applyIssuanceTemplate(credentialRequest credential.CreateCredentialRequest, template issuance.CredentialTemplate, applicationJSON map[string]any, credManifest manifest.CredentialManifest, submission exchange.PresentationSubmission) (*credential.CreateCredentialRequest, error) { - ct, ok := templateMap[od.ID] - if !ok { - logrus.Warnf("Did not find output_descriptor with ID \"%s\" in template. Skipping application.", od.ID) - return nil, nil - } - c, err := getCredentialJSON(applicationJSON, ct, credManifest, submission) + cred, err := getCredentialForInputDescriptor(applicationJSON, template.CredentialInputDescriptor, credManifest, submission) if err != nil { return nil, err } - for k, v := range ct.Data { + for k, v := range template.Data { claimValue := v if vs, ok := v.(string); ok { if strings.HasPrefix(vs, "$") { - claimValue, err = jsonpath.JsonPathLookup(c, vs) + claimValue, err = jsonpath.JsonPathLookup(cred, vs) if err != nil { return nil, errors.Wrapf(err, "looking up json path \"%s\" for key=\"%s\"", vs, k) } @@ -181,48 +184,48 @@ func (s Service) applyIssuanceTemplate(credentialRequest credential.CreateCreden credentialRequest.Data[k] = claimValue } - if ct.Expiry.Time != nil { - credentialRequest.Expiry = ct.Expiry.Time.Format(time.RFC3339) + if template.Expiry.Time != nil { + credentialRequest.Expiry = template.Expiry.Time.Format(time.RFC3339) } - if ct.Expiry.Duration != nil { - credentialRequest.Expiry = s.Clock.Now().Add(*ct.Expiry.Duration).Format(time.RFC3339) + if template.Expiry.Duration != nil { + credentialRequest.Expiry = s.Clock.Now().Add(*template.Expiry.Duration).Format(time.RFC3339) } - credentialRequest.Revocable = ct.Revocable + credentialRequest.Revocable = template.Revocable return &credentialRequest, nil } -func (s Service) applyCredentialOverrides(credentialRequest credential.CreateCredentialRequest, credentialOverrides map[string]model.CredentialOverride, od manifest.OutputDescriptor) credential.CreateCredentialRequest { - if credentialOverride, ok := credentialOverrides[od.ID]; ok { - for k, v := range credentialOverride.Data { - if len(credentialRequest.Data) == 0 { - credentialRequest.Data = make(map[string]any) - } - credentialRequest.Data[k] = v +// applyCredentialOverrides applies the overrides to the credential request +func (s Service) applyCredentialOverrides(credentialRequest credential.CreateCredentialRequest, credentialOverride model.CredentialOverride) credential.CreateCredentialRequest { + for k, v := range credentialOverride.Data { + if len(credentialRequest.Data) == 0 { + credentialRequest.Data = make(map[string]any) } + credentialRequest.Data[k] = v + } - if credentialOverride.Expiry != nil { - credentialRequest.Expiry = credentialOverride.Expiry.Format(time.RFC3339) - } - credentialRequest.Revocable = credentialOverride.Revocable + if credentialOverride.Expiry != nil { + credentialRequest.Expiry = credentialOverride.Expiry.Format(time.RFC3339) } + credentialRequest.Revocable = credentialOverride.Revocable return credentialRequest } -func getCredentialJSON(applicationJSON map[string]any, ct issuance.CredentialTemplate, - credManifest manifest.CredentialManifest, submission exchange.PresentationSubmission) (any, error) { - if ct.CredentialInputDescriptor == "" { - return nil, errors.New("cannot provide input descriptor when credential template does not have input descriptor") +// getCredentialForInputDescriptor returns the credential as JSON for the given input descriptor. +func getCredentialForInputDescriptor(applicationJSON map[string]any, templateInputDescriptorID string, + credManifest manifest.CredentialManifest, submission exchange.PresentationSubmission) (map[string]any, error) { + if templateInputDescriptorID == "" { + return nil, errors.New("cannot provide input descriptor when the credential template does not have input descriptor") } if credManifest.PresentationDefinition.IsEmpty() { - return nil, errors.New("cannot provide input descriptor when manifest does not have presentation definition") + return nil, errors.New("cannot provide input descriptor when the manifest does not have presentation definition") } // Lookup the claim that's sent in the submission. for _, descriptor := range submission.DescriptorMap { - if descriptor.ID == ct.CredentialInputDescriptor { + if descriptor.ID == templateInputDescriptorID { c, err := jsonpath.JsonPathLookup(applicationJSON, descriptor.Path) if err != nil { return nil, errors.Wrapf(err, "looking up json path \"%s\" for submission=\"%s\"", descriptor.Path, descriptor.ID) @@ -231,7 +234,7 @@ func getCredentialJSON(applicationJSON map[string]any, ct issuance.CredentialTem return toCredentialJSON(c) } } - return nil, errors.Errorf("could not find credential for input_descriptor=\"%s\"", ct.CredentialInputDescriptor) + return nil, errors.Errorf("could not find credential for input_descriptor=\"%s\"", templateInputDescriptorID) } func toCredentialJSON(c any) (map[string]any, error) { diff --git a/pkg/service/manifest/service.go b/pkg/service/manifest/service.go index 7a043fcd5..d415bfebf 100644 --- a/pkg/service/manifest/service.go +++ b/pkg/service/manifest/service.go @@ -12,6 +12,7 @@ import ( "github.com/goccy/go-json" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "github.com/tbd54566975/ssi-service/config" credint "github.com/tbd54566975/ssi-service/internal/credential" "github.com/tbd54566975/ssi-service/internal/keyaccess" @@ -261,12 +262,10 @@ func (s Service) ProcessApplicationSubmission(ctx context.Context, request model gotManifest, err := s.storage.GetManifest(ctx, manifestID) applicationID := request.Application.ID if err != nil { - return nil, sdkutil.LoggingErrorMsgf(err, - "problem with retrieving manifest<%s> during application<%s>'s validation", manifestID, applicationID) + return nil, sdkutil.LoggingErrorMsgf(err, "problem with retrieving manifest<%s> during application<%s>'s validation", manifestID, applicationID) } if gotManifest == nil { - return nil, sdkutil.LoggingNewErrorf( - "application<%s> is not valid; a manifest does not exist with id: %s", applicationID, manifestID) + return nil, sdkutil.LoggingNewErrorf("application<%s> is not valid; a manifest does not exist with id: %s", applicationID, manifestID) } opID := opcredential.IDFromResponseID(applicationID) diff --git a/pkg/service/manifest/storage/storage.go b/pkg/service/manifest/storage/storage.go index c5e7ae5bd..8185deeb8 100644 --- a/pkg/service/manifest/storage/storage.go +++ b/pkg/service/manifest/storage/storage.go @@ -8,6 +8,7 @@ import ( "github.com/goccy/go-json" "github.com/pkg/errors" "github.com/sirupsen/logrus" + cred "github.com/tbd54566975/ssi-service/internal/credential" "github.com/tbd54566975/ssi-service/internal/keyaccess" "github.com/tbd54566975/ssi-service/pkg/service/operation/credential" @@ -56,7 +57,7 @@ type Storage struct { func NewManifestStorage(db storage.ServiceStorage) (*Storage, error) { if db == nil { - return nil, errors.New("bolt db reference is nil") + return nil, errors.New("db reference is nil") } return &Storage{db: db}, nil } diff --git a/pkg/service/operation/storage.go b/pkg/service/operation/storage.go index 0378ca6bb..a49fd5381 100644 --- a/pkg/service/operation/storage.go +++ b/pkg/service/operation/storage.go @@ -133,7 +133,7 @@ func (s Storage) DeleteOperation(ctx context.Context, id string) error { func NewOperationStorage(db storage.ServiceStorage) (*Storage, error) { if db == nil { - return nil, errors.New("bolt db reference is nil") + return nil, errors.New("db reference is nil") } return &Storage{db: db}, nil } diff --git a/pkg/service/presentation/storage.go b/pkg/service/presentation/storage.go index 9ff475ebe..10ca30c44 100644 --- a/pkg/service/presentation/storage.go +++ b/pkg/service/presentation/storage.go @@ -9,9 +9,10 @@ import ( "github.com/goccy/go-json" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "github.com/tbd54566975/ssi-service/pkg/service/common" "go.einride.tech/aip/filtering" + "github.com/tbd54566975/ssi-service/pkg/service/common" + opstorage "github.com/tbd54566975/ssi-service/pkg/service/operation/storage" "github.com/tbd54566975/ssi-service/pkg/service/operation/storage/namespace" opsubmission "github.com/tbd54566975/ssi-service/pkg/service/operation/submission" @@ -95,7 +96,7 @@ func (ps *Storage) ListSubmissions(ctx context.Context, filter filtering.Filter) func NewPresentationStorage(db storage.ServiceStorage) (prestorage.Storage, error) { if db == nil { - return nil, errors.New("bolt db reference is nil") + return nil, errors.New("db reference is nil") } return &Storage{db: db, RequestStorage: common.NewRequestStorage(db, presentationRequestNamespace)}, nil } diff --git a/pkg/service/schema/model.go b/pkg/service/schema/model.go index c9d731cd7..7f4f6c585 100644 --- a/pkg/service/schema/model.go +++ b/pkg/service/schema/model.go @@ -3,22 +3,17 @@ package schema import ( "github.com/TBD54566975/ssi-sdk/credential/schema" "github.com/TBD54566975/ssi-sdk/util" - - "github.com/tbd54566975/ssi-service/internal/keyaccess" -) - -const ( - Version1 string = "1.0" ) type CreateSchemaRequest struct { - Author string `json:"author" validate:"required"` - Name string `json:"name" validate:"required"` - Schema schema.JSONSchema `json:"schema" validate:"required"` + Name string `json:"name" validate:"required"` + Description string `json:"description,omitempty"` + Schema schema.JSONSchema `json:"schema" validate:"required"` // If sign == true, the schema will be signed by the author's private key with the specified KID - Sign bool `json:"signed"` - AuthorKID string `json:"authorKid"` + Sign bool `json:"sign,omitempty"` + Issuer string `json:"issuer,omitempty"` + IssuerKID string `json:"issuerKid,omitempty"` } func (csr CreateSchemaRequest) IsValid() bool { @@ -26,18 +21,8 @@ func (csr CreateSchemaRequest) IsValid() bool { } type CreateSchemaResponse struct { - ID string `json:"id"` - Schema schema.VCJSONSchema `json:"schema"` - SchemaJWT *keyaccess.JWT `json:"schemaJwt,omitempty"` -} - -type VerifySchemaRequest struct { - SchemaJWT keyaccess.JWT `json:"schemaJwt"` -} - -type VerifySchemaResponse struct { - Verified bool `json:"verified"` - Reason string `json:"reason,omitempty"` + ID string `json:"id"` + Schema schema.JSONSchema `json:"schema"` } type ListSchemasResponse struct { @@ -49,9 +34,8 @@ type GetSchemaRequest struct { } type GetSchemaResponse struct { - ID string `json:"id"` - Schema schema.VCJSONSchema `json:"schema"` - SchemaJWT *keyaccess.JWT `json:"schemaJwt,omitempty"` + ID string `json:"id"` + Schema schema.JSONSchema `json:"schema"` } type DeleteSchemaRequest struct { diff --git a/pkg/service/schema/service.go b/pkg/service/schema/service.go index a731c8b61..2cd83fdf3 100644 --- a/pkg/service/schema/service.go +++ b/pkg/service/schema/service.go @@ -3,22 +3,18 @@ package schema import ( "context" "fmt" - "time" + "strings" "github.com/TBD54566975/ssi-sdk/credential/schema" - didsdk "github.com/TBD54566975/ssi-sdk/did" "github.com/TBD54566975/ssi-sdk/did/resolution" schemalib "github.com/TBD54566975/ssi-sdk/schema" sdkutil "github.com/TBD54566975/ssi-sdk/util" "github.com/goccy/go-json" "github.com/google/uuid" - "github.com/lestrrat-go/jwx/jws" - "github.com/lestrrat-go/jwx/jwt" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/tbd54566975/ssi-service/config" - "github.com/tbd54566975/ssi-service/internal/keyaccess" "github.com/tbd54566975/ssi-service/pkg/service/framework" "github.com/tbd54566975/ssi-service/pkg/service/keystore" @@ -62,7 +58,8 @@ func (s Service) Config() config.SchemaServiceConfig { return s.config } -func NewSchemaService(config config.SchemaServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service, resolver resolution.Resolver) (*Service, error) { +func NewSchemaService(config config.SchemaServiceConfig, s storage.ServiceStorage, keyStore *keystore.Service, + resolver resolution.Resolver) (*Service, error) { schemaStorage, err := NewSchemaStorage(s) if err != nil { return nil, sdkutil.LoggingErrorMsg(err, "could not instantiate storage for the schema service") @@ -81,7 +78,7 @@ func NewSchemaService(config config.SchemaServiceConfig, s storage.ServiceStorag // CreateSchema houses the main service logic for schema creation. It validates the input, and // produces a schema value that conforms with the VC JSON SchemaID specification. -// TODO(gabe) support data integrity proof generation on schemas, versioning, and more +// TODO(gabe) support data integrity proofs for credential schemas func (s Service) CreateSchema(ctx context.Context, request CreateSchemaRequest) (*CreateSchemaResponse, error) { logrus.Debugf("creating schema: %+v", request) @@ -89,149 +86,48 @@ func (s Service) CreateSchema(ctx context.Context, request CreateSchemaRequest) return nil, sdkutil.LoggingNewErrorf("invalid create schema request: %+v", request) } - schemaBytes, err := json.Marshal(request.Schema) + // validate the schema + jsonSchema := request.Schema + schemaBytes, err := json.Marshal(jsonSchema) if err != nil { return nil, sdkutil.LoggingErrorMsg(err, "could not marshal schema in request") } if err = schemalib.IsValidJSONSchema(string(schemaBytes)); err != nil { return nil, sdkutil.LoggingErrorMsg(err, "provided value is not a valid JSON schema") } - - // create schema - schemaID := uuid.NewString() - schemaValue := schema.VCJSONSchema{ - Type: schema.VCJSONSchemaType, - Version: Version1, - ID: schemaID, - Name: request.Name, - Author: request.Author, - Authored: time.Now().Format(time.RFC3339), - Schema: prepareJSONSchema(schemaID, request.Name, request.Schema), + if !schema.IsSupportedJSONSchemaVersion(jsonSchema.Schema()) { + return nil, sdkutil.LoggingNewErrorf("unsupported schema version: %s", jsonSchema.Schema()) + } + if jsonSchema.ID() != "" { + logrus.Infof("schema has id: %s, which is being overwritten", jsonSchema.ID()) } - storedSchema := StoredSchema{ID: schemaID, Schema: schemaValue} - - // sign the schema - if request.Sign { - signedSchema, err := s.signSchemaJWT(ctx, request.AuthorKID, schemaValue) - if err != nil { - return nil, sdkutil.LoggingError(err) + // set id, name, and description on the schema + schemaID := uuid.NewString() + jsonSchema[schema.JSONSchemaIDProperty] = strings.Join([]string{s.Config().ServiceEndpoint, schemaID}, "/") + if jsonSchema[schema.JSONSchemaNameProperty] != "" && request.Name != "" { + logrus.Infof("schema has name: %s, which is being overwritten", jsonSchema[schema.JSONSchemaNameProperty]) + } + jsonSchema[schema.JSONSchemaNameProperty] = request.Name + if request.Description != "" { + if jsonSchema[schema.JSONSchemaDescriptionProperty] != "" { + logrus.Infof("schema has description: %s, which is being overwritten", jsonSchema[schema.JSONSchemaDescriptionProperty]) } - storedSchema.SchemaJWT = signedSchema + jsonSchema[schema.JSONSchemaDescriptionProperty] = request.Description } + // TODO(gabe) support signing credential schemas + // create schema + storedSchema := StoredSchema{ID: schemaID, Schema: jsonSchema} if err = s.storage.StoreSchema(ctx, storedSchema); err != nil { return nil, sdkutil.LoggingErrorMsg(err, "could not store schema") } - return &CreateSchemaResponse{ID: schemaID, Schema: schemaValue, SchemaJWT: storedSchema.SchemaJWT}, nil -} - -// make sure the schema is well-formed before proceeding -func prepareJSONSchema(id, name string, s schema.JSONSchema) schema.JSONSchema { - if _, ok := s["$id"]; !ok { - s["$id"] = id - } - if _, ok := s["$schema"]; !ok { - s["$schema"] = "https://json-schema.org/draft/2020-12/schema" - } - if _, ok := s["description"]; !ok { - s["description"] = "schema for " + name - } - return s -} - -// signSchemaJWT signs a schema after the key associated with the provided author for the schema as a JWT -func (s Service) signSchemaJWT(ctx context.Context, authorKID string, schema schema.VCJSONSchema) (*keyaccess.JWT, error) { - gotKey, err := s.keyStore.GetKey(ctx, keystore.GetKeyRequest{ID: authorKID}) - if err != nil { - return nil, sdkutil.LoggingErrorMsgf(err, "could not get key for signing schema for authorKID<%s>", authorKID) - } - keyAccess, err := keyaccess.NewJWKKeyAccess(gotKey.Controller, gotKey.ID, gotKey.Key) - if err != nil { - return nil, sdkutil.LoggingErrorMsgf(err, "could not create key access for signing schema for authorKID<%s>", authorKID) - } - schemaJSONBytes, err := sdkutil.ToJSONMap(schema) - if err != nil { - return nil, sdkutil.LoggingErrorMsgf(err, "could not marshal schema for signing for authorKID<%s>", authorKID) - } - schemaToken, err := keyAccess.SignWithDefaults(schemaJSONBytes) - if err != nil { - return nil, sdkutil.LoggingErrorMsgf(err, "could not sign schema for authorKID<%s>", authorKID) - } - if _, err = s.verifySchemaJWT(ctx, keyaccess.JWT(schemaToken)); err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "could not verify schema was signed correctly") - } - return keyaccess.JWTPtr(string(schemaToken)), nil -} - -// VerifySchema verifies a schema's signature and makes sure the schema is compliant with the specification -func (s Service) VerifySchema(ctx context.Context, request VerifySchemaRequest) (*VerifySchemaResponse, error) { - credSchema, err := s.verifySchemaJWT(ctx, request.SchemaJWT) - if err != nil { - return &VerifySchemaResponse{Verified: false, Reason: "could not verify schema's signature: " + err.Error()}, nil - } - - // check the schema is valid against its specification - schemaBytes, err := json.Marshal(credSchema) - if err != nil { - return nil, errors.Wrap(err, "could not marshal schema into json") - } - if err := schema.IsValidCredentialSchema(string(schemaBytes)); err != nil { - return &VerifySchemaResponse{Verified: false, Reason: "schema is not a valid credential schema: " + err.Error()}, nil - } - return &VerifySchemaResponse{Verified: true}, nil -} - -func (s Service) verifySchemaJWT(ctx context.Context, token keyaccess.JWT) (*schema.VCJSONSchema, error) { - // parse headers - headers, err := keyaccess.GetJWTHeaders([]byte(token)) - if err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "could not parse JWT headers") - } - jwtKID, ok := headers.Get(jws.KeyIDKey) - if !ok { - return nil, sdkutil.LoggingNewError("JWT does not contain a kid") - } - kid, ok := jwtKID.(string) - if !ok { - return nil, sdkutil.LoggingNewError("JWT kid is not a string") - } - - // parse token - parsedToken, err := jwt.Parse([]byte(token)) - if err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "could not parse JWT") - } - claims := parsedToken.PrivateClaims() - claimsJSONBytes, err := json.Marshal(claims) - if err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "could not marshal claims") - } - var parsedSchema schema.VCJSONSchema - if err = json.Unmarshal(claimsJSONBytes, &parsedSchema); err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "could not unmarshal claims into schema") - } - resolved, err := s.resolver.Resolve(ctx, parsedSchema.Author) - if err != nil { - return nil, errors.Wrapf(err, "failed to resolve schema author's did: %s", parsedSchema.Author) - } - pubKey, err := didsdk.GetKeyFromVerificationMethod(resolved.Document, kid) - if err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "could not get verification information from schema") - } - verifier, err := keyaccess.NewJWKKeyAccessVerifier(parsedSchema.Author, kid, pubKey) - if err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "could not create schema verifier") - } - if err = verifier.Verify(token); err != nil { - return nil, sdkutil.LoggingErrorMsg(err, "could not verify the schema's signature") - } - return &parsedSchema, nil + return &CreateSchemaResponse{ID: schemaID, Schema: jsonSchema}, nil } func (s Service) ListSchemas(ctx context.Context) (*ListSchemasResponse, error) { - logrus.Debug("listing all schema") + logrus.Debug("listing all schemas") storedSchemas, err := s.storage.ListSchemas(ctx) if err != nil { @@ -240,9 +136,8 @@ func (s Service) ListSchemas(ctx context.Context) (*ListSchemasResponse, error) schemas := make([]GetSchemaResponse, 0, len(storedSchemas)) for _, stored := range storedSchemas { schemas = append(schemas, GetSchemaResponse{ - ID: stored.Schema.ID, - Schema: stored.Schema, - SchemaJWT: stored.SchemaJWT, + ID: stored.ID, + Schema: stored.Schema, }) } @@ -250,7 +145,6 @@ func (s Service) ListSchemas(ctx context.Context) (*ListSchemasResponse, error) } func (s Service) GetSchema(ctx context.Context, request GetSchemaRequest) (*GetSchemaResponse, error) { - logrus.Debugf("getting schema: %s", request.ID) // TODO(gabe) support external schema resolution https://github.com/TBD54566975/ssi-service/issues/125 @@ -261,19 +155,10 @@ func (s Service) GetSchema(ctx context.Context, request GetSchemaRequest) (*GetS if gotSchema == nil { return nil, sdkutil.LoggingNewErrorf("schema with id<%s> could not be found", request.ID) } - return &GetSchemaResponse{Schema: gotSchema.Schema, SchemaJWT: gotSchema.SchemaJWT}, nil -} - -func (s Service) Resolve(ctx context.Context, id string) (*schema.VCJSONSchema, error) { - schemaResponse, err := s.GetSchema(ctx, GetSchemaRequest{ID: id}) - if err != nil { - return nil, sdkutil.LoggingErrorMsgf(err, "could not get schema for id<%s>", id) - } - return &schemaResponse.Schema, nil + return &GetSchemaResponse{Schema: gotSchema.Schema}, nil } func (s Service) DeleteSchema(ctx context.Context, request DeleteSchemaRequest) error { - logrus.Debugf("deleting schema: %s", request.ID) if err := s.storage.DeleteSchema(ctx, request.ID); err != nil { @@ -282,3 +167,12 @@ func (s Service) DeleteSchema(ctx context.Context, request DeleteSchemaRequest) return nil } + +// Resolve wraps our get schema method for exposing schema access to other services +func (s Service) Resolve(ctx context.Context, id string) (*schema.JSONSchema, error) { + gotSchemaResponse, err := s.GetSchema(ctx, GetSchemaRequest{ID: id}) + if err != nil { + return nil, sdkutil.LoggingErrorMsg(err, "resolving schema") + } + return &gotSchemaResponse.Schema, nil +} diff --git a/pkg/service/schema/storage.go b/pkg/service/schema/storage.go index 98a5557c8..3c5e3952c 100644 --- a/pkg/service/schema/storage.go +++ b/pkg/service/schema/storage.go @@ -2,8 +2,8 @@ package schema import ( "context" - "fmt" + "github.com/TBD54566975/ssi-sdk/util" "github.com/goccy/go-json" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -11,8 +11,6 @@ import ( "github.com/TBD54566975/ssi-sdk/credential/schema" "github.com/tbd54566975/ssi-service/pkg/storage" - - "github.com/tbd54566975/ssi-service/internal/keyaccess" ) const ( @@ -20,9 +18,8 @@ const ( ) type StoredSchema struct { - ID string `json:"id"` - Schema schema.VCJSONSchema `json:"schema"` - SchemaJWT *keyaccess.JWT `json:"token,omitempty"` + ID string `json:"id"` + Schema schema.JSONSchema `json:"schema"` } type Storage struct { @@ -31,7 +28,7 @@ type Storage struct { func NewSchemaStorage(db storage.ServiceStorage) (*Storage, error) { if db == nil { - return nil, errors.New("bolt db reference is nil") + return nil, errors.New("db reference is nil") } return &Storage{db: db}, nil } @@ -39,15 +36,11 @@ func NewSchemaStorage(db storage.ServiceStorage) (*Storage, error) { func (ss *Storage) StoreSchema(ctx context.Context, schema StoredSchema) error { id := schema.ID if id == "" { - err := errors.New("could not store schema without an ID") - logrus.WithError(err).Error() - return err + return util.LoggingNewError("could not store schema without an ID") } schemaBytes, err := json.Marshal(schema) if err != nil { - errMsg := fmt.Sprintf("could not store schema: %s", id) - logrus.WithError(err).Error(errMsg) - return errors.Wrapf(err, errMsg) + return util.LoggingErrorMsgf(err, "could not store schema: %s", id) } return ss.db.Write(ctx, namespace, id, schemaBytes) } @@ -55,20 +48,14 @@ func (ss *Storage) StoreSchema(ctx context.Context, schema StoredSchema) error { func (ss *Storage) GetSchema(ctx context.Context, id string) (*StoredSchema, error) { schemaBytes, err := ss.db.Read(ctx, namespace, id) if err != nil { - errMsg := fmt.Sprintf("could not get schema: %s", id) - logrus.WithError(err).Error(errMsg) - return nil, errors.Wrapf(err, errMsg) + return nil, util.LoggingErrorMsgf(err, "could not get schema: %s", id) } if len(schemaBytes) == 0 { - err := fmt.Errorf("schema not found with id: %s", id) - logrus.WithError(err).Error("could not get schema from storage") - return nil, err + return nil, util.LoggingNewErrorf("schema not found with id: %s", id) } var stored StoredSchema - if err := json.Unmarshal(schemaBytes, &stored); err != nil { - errMsg := fmt.Sprintf("could not unmarshal stored schema: %s", id) - logrus.WithError(err).Error(errMsg) - return nil, errors.Wrapf(err, errMsg) + if err = json.Unmarshal(schemaBytes, &stored); err != nil { + return nil, util.LoggingErrorMsgf(err, "could not unmarshal stored schema: %s", id) } return &stored, nil } @@ -77,29 +64,27 @@ func (ss *Storage) GetSchema(ctx context.Context, id string) (*StoredSchema, err func (ss *Storage) ListSchemas(ctx context.Context) ([]StoredSchema, error) { gotSchemas, err := ss.db.ReadAll(ctx, namespace) if err != nil { - errMsg := "could not get all schemas" - logrus.WithError(err).Error(errMsg) - return nil, errors.Wrap(err, errMsg) + return nil, util.LoggingErrorMsg(err, "could not list schemas") } if len(gotSchemas) == 0 { - logrus.Info("no schemas to get") + logrus.Info("no schemas to list") return nil, nil } - var stored []StoredSchema + stored := make([]StoredSchema, 0, len(gotSchemas)) for _, schemaBytes := range gotSchemas { var nextSchema StoredSchema - if err := json.Unmarshal(schemaBytes, &nextSchema); err == nil { - stored = append(stored, nextSchema) + if err = json.Unmarshal(schemaBytes, &nextSchema); err != nil { + logrus.WithError(err).Errorf("could not unmarshal stored schema: %s", string(schemaBytes)) + continue } + stored = append(stored, nextSchema) } return stored, nil } func (ss *Storage) DeleteSchema(ctx context.Context, id string) error { if err := ss.db.Delete(ctx, namespace, id); err != nil { - errMsg := fmt.Sprintf("could not delete schema: %s", id) - logrus.WithError(err).Error(errMsg) - return errors.Wrapf(err, errMsg) + return util.LoggingErrorMsgf(err, "could not delete schema: %s", id) } return nil } diff --git a/pkg/service/webhook/storage.go b/pkg/service/webhook/storage.go index 18bab6401..6bd7a41e1 100644 --- a/pkg/service/webhook/storage.go +++ b/pkg/service/webhook/storage.go @@ -19,7 +19,7 @@ type Storage struct { func NewWebhookStorage(db storage.ServiceStorage) (*Storage, error) { if db == nil { - return nil, errors.New("bolt db reference is nil") + return nil, errors.New("db reference is nil") } return &Storage{db: db}, nil }