diff --git a/vcr/pe/schema/README.md b/vcr/pe/schema/README.md new file mode 100644 index 0000000000..bf6b681e8b --- /dev/null +++ b/vcr/pe/schema/README.md @@ -0,0 +1,3 @@ +Schemas files were taken from: +- https://github.com/decentralized-identity/presentation-exchange/tree/main/schemas +- https://github.com/decentralized-identity/claim-format-registry/tree/main/schemas \ No newline at end of file diff --git a/vcr/pe/schema/gen/main.go b/vcr/pe/schema/gen/main.go index 2eb767ecd4..7b3e4f0faf 100644 --- a/vcr/pe/schema/gen/main.go +++ b/vcr/pe/schema/gen/main.go @@ -44,7 +44,7 @@ func main() { os.Exit(1) } - f, err := os.OpenFile("../generated.go", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) + f, err := os.OpenFile("generated.go", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { fmt.Fprintln(os.Stderr, "Error opening output file: ", err) diff --git a/vcr/pe/schema/v2/input-descriptor.json b/vcr/pe/schema/v2/input-descriptor.json new file mode 100644 index 0000000000..2112e900f8 --- /dev/null +++ b/vcr/pe/schema/v2/input-descriptor.json @@ -0,0 +1,220 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Input Descriptor", + "definitions": { + "status_directive": { + "type": "object", + "additionalProperties": false, + "properties": { + "directive": { + "type": "string", + "enum": [ + "required", + "allowed", + "disallowed" + ] + }, + "type": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + } + }, + "field": { + "type": "object", + "oneOf": [ + { + "properties": { + "id": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "path": { + "type": "array", + "items": { + "type": "string" + } + }, + "purpose": { + "type": "string" + }, + "intent_to_retain": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "filter": { + "$ref": "http://json-schema.org/draft-07/schema#" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "properties": { + "id": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "path": { + "type": "array", + "items": { + "type": "string" + } + }, + "purpose": { + "type": "string" + }, + "intent_to_retain": { + "type": "boolean" + }, + "filter": { + "$ref": "http://json-schema.org/draft-07/schema#" + }, + "name": { + "type": "string" + }, + "predicate": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + } + }, + "required": [ + "path", + "filter", + "predicate" + ], + "additionalProperties": false + } + ] + } + }, + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "group": { + "type": "array", + "items": { + "type": "string" + } + }, + "constraints": { + "type": "object", + "additionalProperties": false, + "properties": { + "limit_disclosure": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + }, + "statuses": { + "type": "object", + "additionalProperties": false, + "properties": { + "active": { + "$ref": "#/definitions/status_directive" + }, + "suspended": { + "$ref": "#/definitions/status_directive" + }, + "revoked": { + "$ref": "#/definitions/status_directive" + } + } + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/definitions/field" + } + }, + "subject_is_issuer": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + }, + "is_holder": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "field_id": { + "type": "array", + "items": { + "type": "string" + } + }, + "directive": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + } + }, + "required": [ + "field_id", + "directive" + ] + } + }, + "same_subject": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "field_id": { + "type": "array", + "items": { + "type": "string" + } + }, + "directive": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + } + }, + "required": [ + "field_id", + "directive" + ] + } + } + } + } + }, + "required": [ + "id" + ] +} diff --git a/vcr/pe/schema/v2/presentation-definition-envelope.json b/vcr/pe/schema/v2/presentation-definition-envelope.json new file mode 100644 index 0000000000..872a1e3966 --- /dev/null +++ b/vcr/pe/schema/v2/presentation-definition-envelope.json @@ -0,0 +1,353 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Presentation Definition Envelope", + "definitions": { + "status_directive": { + "type": "object", + "additionalProperties": false, + "properties": { + "directive": { + "type": "string", + "enum": [ + "required", + "allowed", + "disallowed" + ] + }, + "type": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + } + } + }, + "field": { + "type": "object", + "oneOf": [ + { + "properties": { + "id": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "path": { + "type": "array", + "items": { + "type": "string" + } + }, + "purpose": { + "type": "string" + }, + "name": { + "type": "string" + }, + "intent_to_retain": { + "type": "boolean" + }, + "filter": { + "$ref": "http://json-schema.org/draft-07/schema#" + } + }, + "required": [ + "path" + ], + "additionalProperties": false + }, + { + "properties": { + "id": { + "type": "string" + }, + "optional": { + "type": "boolean" + }, + "path": { + "type": "array", + "items": { + "type": "string" + } + }, + "purpose": { + "type": "string" + }, + "intent_to_retain": { + "type": "boolean" + }, + "filter": { + "$ref": "http://json-schema.org/draft-07/schema#" + }, + "name": { + "type": "string" + }, + "predicate": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + } + }, + "required": [ + "path", + "filter", + "predicate" + ], + "additionalProperties": false + } + ] + }, + "input_descriptor": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "format": { + "$ref": "http://identity.foundation/claim-format-registry/schemas/presentation-definition-claim-format-designations.json" + }, + "group": { + "type": "array", + "items": { + "type": "string" + } + }, + "constraints": { + "type": "object", + "additionalProperties": false, + "properties": { + "limit_disclosure": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + }, + "statuses": { + "type": "object", + "additionalProperties": false, + "properties": { + "active": { + "$ref": "#/definitions/status_directive" + }, + "suspended": { + "$ref": "#/definitions/status_directive" + }, + "revoked": { + "$ref": "#/definitions/status_directive" + } + } + }, + "fields": { + "type": "array", + "items": { + "$ref": "#/definitions/field" + } + }, + "subject_is_issuer": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + }, + "is_holder": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "field_id": { + "type": "array", + "items": { + "type": "string" + } + }, + "directive": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + } + }, + "required": [ + "field_id", + "directive" + ] + } + }, + "same_subject": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "field_id": { + "type": "array", + "items": { + "type": "string" + } + }, + "directive": { + "type": "string", + "enum": [ + "required", + "preferred" + ] + } + }, + "required": [ + "field_id", + "directive" + ] + } + } + } + } + }, + "required": [ + "id", + "constraints" + ] + }, + "submission_requirement": { + "type": "object", + "oneOf": [ + { + "properties": { + "name": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "rule": { + "type": "string", + "enum": [ + "all", + "pick" + ] + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 0 + }, + "max": { + "type": "integer", + "minimum": 0 + }, + "from": { + "type": "string" + } + }, + "required": [ + "rule", + "from" + ], + "additionalProperties": false + }, + { + "properties": { + "name": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "rule": { + "type": "string", + "enum": [ + "all", + "pick" + ] + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 0 + }, + "max": { + "type": "integer", + "minimum": 0 + }, + "from_nested": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/submission_requirement" + } + } + }, + "required": [ + "rule", + "from_nested" + ], + "additionalProperties": false + } + ] + }, + "presentation_definition": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "format": { + "$ref": "http://identity.foundation/claim-format-registry/schemas/presentation-definition-claim-format-designations.json#" + }, + "frame": { + "type": "object", + "additionalProperties": true + }, + "submission_requirements": { + "type": "array", + "items": { + "$ref": "#/definitions/submission_requirement" + } + }, + "input_descriptors": { + "type": "array", + "items": { + "$ref": "#/definitions/input_descriptor" + } + } + }, + "required": [ + "id", + "input_descriptors" + ], + "additionalProperties": false + } + }, + "type": "object", + "properties": { + "presentation_definition": { + "$ref": "#/definitions/presentation_definition" + } + } +} diff --git a/vcr/pe/schema/v2/presentation_definition.json b/vcr/pe/schema/v2/presentation-definition.json similarity index 100% rename from vcr/pe/schema/v2/presentation_definition.json rename to vcr/pe/schema/v2/presentation-definition.json diff --git a/vcr/pe/schema/v2/presentation_submission.json b/vcr/pe/schema/v2/presentation-submission.json similarity index 100% rename from vcr/pe/schema/v2/presentation_submission.json rename to vcr/pe/schema/v2/presentation-submission.json diff --git a/vcr/pe/schema/v2/schema.go b/vcr/pe/schema/v2/schema.go index 7046996574..44de55fdd8 100644 --- a/vcr/pe/schema/v2/schema.go +++ b/vcr/pe/schema/v2/schema.go @@ -16,36 +16,34 @@ * */ -// This package implements v2.0.0 of the Presentation Exchange specification +// Package v2 implements v2.0.0 of the Presentation Exchange specification package v2 import ( "bytes" + "embed" _ "embed" "fmt" "github.com/santhosh-tekuri/jsonschema" "github.com/santhosh-tekuri/jsonschema/loader" "io" + "io/fs" + "strings" ) -//go:embed json-schema-draft-07.json -var jsonSchemaDraft07SchemaData []byte - -const presentationDefinitionSchemaURL = "http://identity.foundation/presentation-exchange/schemas/presentation-definition.json" - -//go:embed presentation_definition.json -var presentationDefinitionSchemaData []byte - -//go:embed presentation-definition-claim-format-designations.json -var presentationDefinitionClaimFormatDesignationsSchemaData []byte - -//go:embed presentation-submission-claim-format-designations.json -var presentationSubmissionClaimFormatDesignationsSchemaData []byte - -const presentationSubmissionSchemaURL = "https://identity.foundation/presentation-exchange/schemas/presentation-submission.json" +const ( + inputDescriptor = "http://identity.foundation/presentation-exchange/schemas/input-descriptor.json" + presentationDefinitionEnvelope = "http://identity.foundation/presentation-exchange/schemas/presentation-definition-envelope.json" + presentationDefinition = "http://identity.foundation/presentation-exchange/schemas/presentation-definition.json" + presentationSubmission = "http://identity.foundation/presentation-exchange/schemas/presentation-submission.json" + submissionRequirement = "http://identity.foundation/presentation-exchange/schemas/submission-requirement.json" + submissionRequirements = "http://identity.foundation/presentation-exchange/schemas/submission-requirements.json" + presentationSubmissionClaimFormatDesignations = "http://identity.foundation/claim-format-registry/schemas/presentation-submission-claim-format-designations.json" + presentationDefinitionClaimFormatDesignations = "http://identity.foundation/claim-format-registry/schemas/presentation-definition-claim-format-designations.json" +) -//go:embed presentation_submission.json -var presentationSubmissionSchemaData []byte +//go:embed *.json +var schemaFiles embed.FS // PresentationDefinition is the JSON schema for a presentation definition. var PresentationDefinition *jsonschema.Schema @@ -61,20 +59,43 @@ func init() { } compiler := jsonschema.NewCompiler() compiler.Draft = jsonschema.Draft7 - resources := map[string][]byte{ - "http://json-schema.org/draft-07/schema": jsonSchemaDraft07SchemaData, - "http://identity.foundation/claim-format-registry/schemas/presentation-definition-claim-format-designations.json": presentationDefinitionClaimFormatDesignationsSchemaData, - presentationDefinitionSchemaURL: presentationDefinitionSchemaData, - "http://identity.foundation/claim-format-registry/schemas/presentation-submission-claim-format-designations.json": presentationSubmissionClaimFormatDesignationsSchemaData, - presentationSubmissionSchemaURL: presentationSubmissionSchemaData, + if err := loadSchemas(schemaFiles, compiler); err != nil { + panic(err) } - for u, data := range resources { - if err := compiler.AddResource(u, bytes.NewReader(data)); err != nil { - panic(fmt.Errorf("error compiling schema %s: %w", u, err)) + PresentationDefinition = compiler.MustCompile(presentationDefinition) + PresentationSubmission = compiler.MustCompile(presentationSubmission) +} + +func loadSchemas(reader fs.ReadFileFS, compiler *jsonschema.Compiler) error { + var resources = map[string]string{ + "http://json-schema.org/draft-07/schema": "json-schema-draft-07.json", + } + schemaURLs := []string{ + inputDescriptor, + presentationDefinitionEnvelope, + presentationDefinition, + presentationSubmission, + submissionRequirement, + submissionRequirements, + presentationSubmissionClaimFormatDesignations, + presentationDefinitionClaimFormatDesignations, + } + for _, schemaURL := range schemaURLs { + // Last part of schema URL matches the embedded file's name + parts := strings.Split(schemaURL, "/") + fileName := parts[len(parts)-1] + resources[schemaURL] = fileName + } + for schemaURL, fileName := range resources { + data, err := reader.ReadFile(fileName) + if err != nil { + return fmt.Errorf("error reading schema file %s: %w", fileName, err) + } + if err := compiler.AddResource(schemaURL, bytes.NewReader(data)); err != nil { + return fmt.Errorf("error compiling schema %s: %w", schemaURL, err) } } - PresentationDefinition = compiler.MustCompile(presentationDefinitionSchemaURL) - PresentationSubmission = compiler.MustCompile(presentationSubmissionSchemaURL) + return nil } // Validate validates the given data against the given schema. diff --git a/vcr/pe/schema/v2/submission-requirement.json b/vcr/pe/schema/v2/submission-requirement.json new file mode 100644 index 0000000000..9650087ef1 --- /dev/null +++ b/vcr/pe/schema/v2/submission-requirement.json @@ -0,0 +1,50 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Presentation Submission Requirement", + "definitions": { + "submission_requirement": { + "type": "object", + "oneOf": [ + { + "properties": { + "name": { "type": "string" }, + "purpose": { "type": "string" }, + "rule": { + "type": "string", + "enum": ["all", "pick"] + }, + "count": { "type": "integer", "minimum": 1 }, + "min": { "type": "integer", "minimum": 0 }, + "max": { "type": "integer", "minimum": 0 }, + "from": { "type": "string" } + }, + "required": ["rule", "from"], + "additionalProperties": false + }, + { + "properties": { + "name": { "type": "string" }, + "purpose": { "type": "string" }, + "rule": { + "type": "string", + "enum": ["all", "pick"] + }, + "count": { "type": "integer", "minimum": 1 }, + "min": { "type": "integer", "minimum": 0 }, + "max": { "type": "integer", "minimum": 0 }, + "from_nested": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/submission_requirement" + } + } + }, + "required": ["rule", "from_nested"], + "additionalProperties": false + } + ] + } + }, + "$ref": "#/definitions/submission_requirement" +} \ No newline at end of file diff --git a/vcr/pe/schema/v2/submission-requirements.json b/vcr/pe/schema/v2/submission-requirements.json new file mode 100644 index 0000000000..c04701eb81 --- /dev/null +++ b/vcr/pe/schema/v2/submission-requirements.json @@ -0,0 +1,102 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Submission Requirements", + "definitions": { + "submission_requirements": { + "type": "object", + "oneOf": [ + { + "properties": { + "name": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "rule": { + "type": "string", + "enum": [ + "all", + "pick" + ] + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 0 + }, + "max": { + "type": "integer", + "minimum": 0 + }, + "from": { + "type": "string" + } + }, + "required": [ + "rule", + "from" + ], + "additionalProperties": false + }, + { + "properties": { + "name": { + "type": "string" + }, + "purpose": { + "type": "string" + }, + "rule": { + "type": "string", + "enum": [ + "all", + "pick" + ] + }, + "count": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 0 + }, + "max": { + "type": "integer", + "minimum": 0 + }, + "from_nested": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/submission_requirements" + } + } + }, + "required": [ + "rule", + "from_nested" + ], + "additionalProperties": false + } + ] + } + }, + "type": "object", + "properties": { + "submission_requirements": { + "type": "array", + "items": { + "$ref": "#/definitions/submission_requirements" + } + } + }, + "required": [ + "submission_requirements" + ], + "additionalProperties": false +} \ No newline at end of file