diff --git a/src/components/SchemaReference.js b/src/components/SchemaReference.js index 5a572d4f..ba65edfa 100644 --- a/src/components/SchemaReference.js +++ b/src/components/SchemaReference.js @@ -8,6 +8,14 @@ const slugify = (text) => const isObject = (v) => v && typeof v === 'object' && !Array.isArray(v); +const refToDefName = (ref) => { + if (typeof ref !== 'string') return null; + if (ref.startsWith('#/$defs/')) return ref.slice('#/$defs/'.length); + if (ref.startsWith('#/definitions/')) + return ref.slice('#/definitions/'.length); + return null; +}; + function formatType(cellSchema) { if (!cellSchema) return 'N/A'; @@ -206,7 +214,13 @@ function Markdown({ text }) { return ; } -function PropertiesTable({ title, description, properties, required }) { +function PropertiesTable({ + title, + description, + properties, + required, + defaults, +}) { if (!properties || Object.keys(properties).length === 0) return null; return ( @@ -242,10 +256,42 @@ function PropertiesTable({ title, description, properties, required }) { const isRequired = Array.isArray(required) ? required.includes(name) : false; - const defaultValue = + const explicitDefault = schema && Object.prototype.hasOwnProperty.call(schema, 'default') - ? JSON.stringify(schema.default) - : 'N/A'; + ? schema.default + : undefined; + const inferredDefault = + defaults && Object.prototype.hasOwnProperty.call(defaults, name) + ? defaults[name] + : undefined; + const chosenDefault = + explicitDefault !== undefined + ? explicitDefault + : inferredDefault !== undefined + ? inferredDefault + : undefined; + + // Link to the referenced definition for non-primitive defaults (objects/arrays) when possible + let defaultCell; + if (chosenDefault === undefined) { + defaultCell = 'N/A'; + } else if ( + typeof chosenDefault === 'object' && + chosenDefault !== null + ) { + const defName = schema ? refToDefName(schema.$ref) : null; + if (defName) { + defaultCell = ( + <> + See {defName} + + ); + } else { + defaultCell = JSON.stringify(chosenDefault); + } + } else { + defaultCell = JSON.stringify(chosenDefault); + } return ( @@ -265,7 +311,7 @@ function PropertiesTable({ title, description, properties, required }) { {isRequired ? 'YES' : 'NO'} - {defaultValue} + {defaultCell} ); })} @@ -402,6 +448,7 @@ function DefinitionSection({ name, schema }) { ) : ( // Fallback simple table for non-object schemas @@ -445,6 +492,54 @@ export default function SchemaReference({ schemaUrl }) { const [error, setError] = useState(null); const [loading, setLoading] = useState(true); + const buildDefDefaults = (root) => { + if (!root || !isObject(root)) return {}; + const defs = root.$defs || root.definitions || {}; + const defDefaults = {}; + + const feed = (defName, defSchema, value) => { + if (!defName || !defSchema) return; + if (!isObject(value)) { + // Record scalar/array as the default value of the referenced node when used as a property. + // For nested object defaults we handle below. + return; + } + const props = (defSchema && defSchema.properties) || {}; + if (!isObject(props)) return; + if (!defDefaults[defName]) defDefaults[defName] = {}; + for (const [propName, propSchema] of Object.entries(props)) { + if (!Object.prototype.hasOwnProperty.call(value, propName)) continue; + const propValue = value[propName]; + // Always record the value for the property at this level for display + defDefaults[defName][propName] = propValue; + // If the property itself references another definition and the default value is an object, + // propagate deeper so nested definition sections can show their own inferred defaults. + const subRefName = propSchema && refToDefName(propSchema.$ref); + if (subRefName) { + const subDefSchema = defs[subRefName]; + if (subDefSchema) feed(subRefName, subDefSchema, propValue); + } + } + }; + + const rootProps = (root && root.properties) || {}; + for (const [, propSchema] of Object.entries(rootProps)) { + const defName = propSchema && refToDefName(propSchema.$ref); + if (!defName) continue; + const defSchema = defs[defName]; + if (!defSchema) continue; + if ( + propSchema && + Object.prototype.hasOwnProperty.call(propSchema, 'default') + ) { + const defaultValue = propSchema.default; + feed(defName, defSchema, defaultValue); + } + } + + return defDefaults; + }; + useEffect(() => { let cancelled = false; async function run() { @@ -467,6 +562,11 @@ export default function SchemaReference({ schemaUrl }) { }; }, [schemaUrl]); + const inferredDefaults = useMemo( + () => buildDefDefaults(schema || {}), + [schema], + ); + if (loading) return

Loading schema…

; if (error) return

{error}

; if (!schema) return

No schema loaded.

; @@ -496,9 +596,21 @@ export default function SchemaReference({ schemaUrl }) { - {Object.entries(defs).map(([name, defSchema]) => ( - - ))} + {Object.entries(defs).map(([name, defSchema]) => { + const schemaWithDefaults = + (defSchema && { + ...defSchema, + __inferredDefaults: inferredDefaults[name], + }) || + defSchema; + return ( + + ); + })} ); } diff --git a/static/schemas/Builder.schema.json b/static/schemas/Builder.schema.json index df09f82a..eeafce90 100644 --- a/static/schemas/Builder.schema.json +++ b/static/schemas/Builder.schema.json @@ -6,20 +6,14 @@ "properties": { "claim_version": { "description": "The version of the claim. Defaults to 2.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint8", "minimum": 0, "maximum": 255 }, "vendor": { "description": "Optional prefix added to the generated Manifest Label\nThis is typically a reverse domain name.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "claim_generator_info": { "description": "Claim Generator Info is always required with an entry", @@ -36,20 +30,14 @@ }, "metadata": { "description": "Optional manifest metadata. This will be deprecated in the future; not recommended to use.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssertionMetadata" } }, "title": { "description": "A human-readable title, generally source filename.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "format": { "description": "The format of the source file as a MIME type.", @@ -90,27 +78,18 @@ }, "redactions": { "description": "A list of redactions - URIs to redacted assertions.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } }, "label": { "description": "Allows you to pre-define the manifest label, which must be unique.\nNot intended for general use. If not set, it will be assigned automatically.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "remote_url": { "description": "Optional remote URL for the manifest", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "no_embed": { "description": "If true, the manifest store will not be embedded in the asset on sign", @@ -118,10 +97,7 @@ }, "base_path": { "description": "Base path to search for resources.", - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "deprecated": true }, "intent": { @@ -145,10 +121,7 @@ } } }, - "required": [ - "no_embed", - "timestamp_manifest_labels" - ], + "required": ["no_embed", "timestamp_manifest_labels"], "$defs": { "ClaimGeneratorInfo": { "description": "Description of the claim generator, or the software used in generating the claim.\n\nThis structure is also used for actions softwareAgent", @@ -160,10 +133,7 @@ }, "version": { "description": "A human readable string of the product's version", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "icon": { "description": "hashed URI to the icon (either embedded or remote)", @@ -178,15 +148,10 @@ }, "operating_system": { "description": "A human readable string of the OS the claim generator is running on", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "name" - ], + "required": ["name"], "additionalProperties": true }, "UriOrResource": { @@ -213,33 +178,21 @@ }, "data_types": { "description": "More detailed data types as defined in the C2PA spec.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssetType" } }, "alg": { "description": "The algorithm used to hash the resource (if applicable).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hash": { "description": "The hash of the resource (if applicable).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "format", - "identifier" - ] + "required": ["format", "identifier"] }, "AssetType": { "type": "object", @@ -248,15 +201,10 @@ "type": "string" }, "version": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "type" - ] + "required": ["type"] }, "HashedUri": { "description": "A `HashedUri` provides a reference to content available within the same\nmanifest store.\n\nThis is described in [§8.3, URI References], of the C2PA Technical\nSpecification.\n\n[§8.3, URI References]: https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_uri_references", @@ -268,10 +216,7 @@ }, "alg": { "description": "A string identifying the cryptographic hash algorithm used to compute\nthe hash", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hash": { "description": "Byte string containing the hash value", @@ -284,20 +229,14 @@ } } }, - "required": [ - "url", - "hash" - ] + "required": ["url", "hash"] }, "AssertionMetadata": { "description": "The AssertionMetadata structure can be used as part of other assertions or on its own to reference others", "type": "object", "properties": { "reviewRatings": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ReviewRating" } @@ -333,10 +272,7 @@ ] }, "localizations": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "object", "additionalProperties": { @@ -368,10 +304,7 @@ "type": "string" }, "code": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "value": { "type": "integer", @@ -380,10 +313,7 @@ "maximum": 255 } }, - "required": [ - "explanation", - "value" - ] + "required": ["explanation", "value"] }, "DateT": { "type": "string" @@ -398,25 +328,17 @@ }, "details": { "description": "A human-readable string giving details about the source of the assertion data.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "actors": { "description": "A list of [`Actor`]s associated with this source.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/Actor" } } }, - "required": [ - "type" - ] + "required": ["type"] }, "Actor": { "description": "Identifies a person responsible for an action.", @@ -424,17 +346,11 @@ "properties": { "identifier": { "description": "An identifier for a human actor, used when the \"type\" is `humanEntry.identified`.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "credentials": { "description": "List of references to W3C Verifiable Credentials.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/HashedUri" } @@ -454,24 +370,15 @@ }, "name": { "description": "A free-text string representing a human-readable name for the region which might be used in a user interface.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "identifier": { "description": "A free-text string representing a machine-readable, unique to this assertion, identifier for the region.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "type": { "description": "A value from a controlled vocabulary such as or an entity-specific\nvalue (e.g., com.litware.newType) that represents the type of thing(s) depicted by a region.\n\nNote this field serializes/deserializes into the name `type`.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "role": { "description": "A value from our controlled vocabulary or an entity-specific value (e.g., com.litware.coolArea) that represents\nthe role of a region among other regions.", @@ -486,10 +393,7 @@ }, "description": { "description": "A free-text string.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "metadata": { "description": "Additional information about the asset.", @@ -503,9 +407,7 @@ ] } }, - "required": [ - "region" - ] + "required": ["region"] }, "Range": { "description": "A spatial, temporal, frame, or textual range describing the region of interest.", @@ -571,9 +473,7 @@ ] } }, - "required": [ - "type" - ] + "required": ["type"] }, "RangeType": { "description": "The type of range for the region of interest.", @@ -623,43 +523,27 @@ }, "width": { "description": "The width for rectangles or diameter for circles.\n\nThis field can be ignored for polygons.", - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "height": { "description": "The height of a rectnagle.\n\nThis field can be ignored for circles and polygons.", - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "inside": { "description": "If the range is inside the shape.\n\nThe default value is true.", - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] }, "vertices": { "description": "The vertices of the polygon.\n\nThis field can be ignored for rectangles and circles.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/Coordinate" } } }, - "required": [ - "type", - "unit", - "origin" - ] + "required": ["type", "unit", "origin"] }, "ShapeType": { "description": "The type of shape for the range.", @@ -711,10 +595,7 @@ "format": "double" } }, - "required": [ - "x", - "y" - ] + "required": ["x", "y"] }, "Time": { "description": "A temporal range representing a starting time to an ending time.", @@ -727,17 +608,11 @@ }, "start": { "description": "The start time or the start of the asset if not present.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "end": { "description": "The end time or the end of the asset if not present.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -757,18 +632,12 @@ "properties": { "start": { "description": "The start of the frame or the end of the asset if not present.\n\nThe first frame/page starts at 0.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "end": { "description": "The end of the frame inclusive or the end of the asset if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" } } @@ -785,9 +654,7 @@ } } }, - "required": [ - "selectors" - ] + "required": ["selectors"] }, "TextSelectorRange": { "description": "One or two [`TextSelector`][TextSelector] identifiying the range to select.", @@ -809,9 +676,7 @@ ] } }, - "required": [ - "selector" - ] + "required": ["selector"] }, "TextSelector": { "description": "Selects a range of text via a fragment identifier.\n\nThis is modeled after the W3C Web Annotation selector model.", @@ -823,24 +688,16 @@ }, "start": { "description": "The start character offset or the start of the fragment if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "end": { "description": "The end character offset or the end of the fragment if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" } }, - "required": [ - "fragment" - ] + "required": ["fragment"] }, "Item": { "description": "Description of the boundaries of an identified range.", @@ -855,10 +712,7 @@ "type": "string" } }, - "required": [ - "identifier", - "value" - ] + "required": ["identifier", "value"] }, "Role": { "description": "A role describing the region.", @@ -916,38 +770,23 @@ "properties": { "title": { "description": "A human-readable title, generally source filename.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "format": { "description": "The format of the source file as a MIME type.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "document_id": { "description": "Document ID from `xmpMM:DocumentID` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "instance_id": { "description": "Instance ID from `xmpMM:InstanceID` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "provenance": { "description": "URI from `dcterms:provenance` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "thumbnail": { "description": "A thumbnail image capturing the visual state at the time of import.\n\nA tuple of thumbnail MIME format (for example `image/jpeg`) and binary bits of the image.", @@ -962,10 +801,7 @@ }, "hash": { "description": "An optional hash of the asset to prevent duplicates.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "relationship": { "description": "Set to `ParentOf` if this is the parent ingredient.\n\nThere can only be one parent ingredient in the ingredients.", @@ -974,17 +810,11 @@ }, "active_manifest": { "description": "The active manifest label (if one exists).\n\nIf this ingredient has a [`ManifestStore`],\nthis will hold the label of the active [`Manifest`].\n\n[`Manifest`]: crate::Manifest\n[`ManifestStore`]: crate::ManifestStore", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "validation_status": { "description": "Validation status (Ingredient v1 & v2)", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ValidationStatus" } @@ -1013,17 +843,11 @@ }, "description": { "description": "Additional description of the ingredient.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "informational_URI": { "description": "URI to an informational page about the ingredient or its data.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "metadata": { "description": "Any additional [`Metadata`] as defined in the C2PA spec.\n\n[`Metadata`]: crate::Metadata", @@ -1038,10 +862,7 @@ }, "data_types": { "description": "Additional information about the data's type to the ingredient V2 structure.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssetType" } @@ -1059,16 +880,10 @@ }, "label": { "description": "The ingredient's label as assigned in the manifest.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "ocsp_responses": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ResourceRef" } @@ -1103,28 +918,17 @@ "type": "string" }, "url": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "explanation": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "success": { - "type": [ - "boolean", - "null" - ], + "type": ["boolean", "null"], "writeOnly": true } }, - "required": [ - "code" - ] + "required": ["code"] }, "ValidationResults": { "description": "A map of validation results for a manifest store.\n\nThe map contains the validation results for the active manifest and any ingredient deltas.\nIt is normal for there to be many", @@ -1143,10 +947,7 @@ }, "ingredientDeltas": { "description": "List of any changes/deltas between the current and previous validation results for each ingredient's\nmanifest. Present if the the ingredient is a C2PA asset.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/IngredientDeltaValidationResult" } @@ -1178,11 +979,7 @@ } } }, - "required": [ - "success", - "informational", - "failure" - ] + "required": ["success", "informational", "failure"] }, "IngredientDeltaValidationResult": { "description": "Represents any changes or deltas between the current and previous validation results for an ingredient's manifest.", @@ -1197,10 +994,7 @@ "$ref": "#/$defs/StatusCodes" } }, - "required": [ - "ingredientAssertionURI", - "validationDeltas" - ] + "required": ["ingredientAssertionURI", "validationDeltas"] }, "AssertionDefinition": { "description": "Defines an assertion that consists of a label that can be either\na C2PA-defined assertion label or a custom label in reverse domain format.", @@ -1230,26 +1024,16 @@ "type": "boolean" } }, - "required": [ - "label", - "data" - ] + "required": ["label", "data"] }, "AssertionData": { "description": "This allows the assertion to be expressed as CBOR or JSON.\nThe default is CBOR unless you specify that an assertion should be JSON.", - "anyOf": [ - true - ] + "anyOf": [true] }, "ManifestAssertionKind": { "description": "Assertions in C2PA can be stored in several formats", "type": "string", - "enum": [ - "Cbor", - "Json", - "Binary", - "Uri" - ] + "enum": ["Cbor", "Json", "Binary", "Uri"] }, "BuilderIntent": { "description": "Represents the type of builder flow being used.\n\nThis determines how the builder will be used, such as creating a new asset, opening an existing asset,\nor updating an existing asset.", @@ -1262,9 +1046,7 @@ "$ref": "#/$defs/DigitalSourceType" } }, - "required": [ - "create" - ], + "required": ["create"], "additionalProperties": false }, { @@ -1402,4 +1184,4 @@ ] } } -} \ No newline at end of file +} diff --git a/static/schemas/ManifestDefinition.schema.json b/static/schemas/ManifestDefinition.schema.json index f648085c..62e068d6 100644 --- a/static/schemas/ManifestDefinition.schema.json +++ b/static/schemas/ManifestDefinition.schema.json @@ -6,20 +6,14 @@ "properties": { "claim_version": { "description": "The version of the claim. Defaults to 2.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint8", "minimum": 0, "maximum": 255 }, "vendor": { "description": "Optional prefix added to the generated Manifest Label\nThis is typically a reverse domain name.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "claim_generator_info": { "description": "Claim Generator Info is always required with an entry", @@ -36,20 +30,14 @@ }, "metadata": { "description": "Optional manifest metadata. This will be deprecated in the future; not recommended to use.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssertionMetadata" } }, "title": { "description": "A human-readable title, generally source filename.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "format": { "description": "The format of the source file as a MIME type.", @@ -90,20 +78,14 @@ }, "redactions": { "description": "A list of redactions - URIs to redacted assertions.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } }, "label": { "description": "Allows you to pre-define the manifest label, which must be unique.\nNot intended for general use. If not set, it will be assigned automatically.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, "$defs": { @@ -117,10 +99,7 @@ }, "version": { "description": "A human readable string of the product's version", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "icon": { "description": "hashed URI to the icon (either embedded or remote)", @@ -135,15 +114,10 @@ }, "operating_system": { "description": "A human readable string of the OS the claim generator is running on", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "name" - ], + "required": ["name"], "additionalProperties": true }, "UriOrResource": { @@ -170,33 +144,21 @@ }, "data_types": { "description": "More detailed data types as defined in the C2PA spec.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssetType" } }, "alg": { "description": "The algorithm used to hash the resource (if applicable).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hash": { "description": "The hash of the resource (if applicable).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "format", - "identifier" - ] + "required": ["format", "identifier"] }, "AssetType": { "type": "object", @@ -205,15 +167,10 @@ "type": "string" }, "version": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "type" - ] + "required": ["type"] }, "HashedUri": { "description": "A `HashedUri` provides a reference to content available within the same\nmanifest store.\n\nThis is described in [§8.3, URI References], of the C2PA Technical\nSpecification.\n\n[§8.3, URI References]: https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_uri_references", @@ -225,10 +182,7 @@ }, "alg": { "description": "A string identifying the cryptographic hash algorithm used to compute\nthe hash", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hash": { "description": "Byte string containing the hash value", @@ -241,20 +195,14 @@ } } }, - "required": [ - "url", - "hash" - ] + "required": ["url", "hash"] }, "AssertionMetadata": { "description": "The AssertionMetadata structure can be used as part of other assertions or on its own to reference others", "type": "object", "properties": { "reviewRatings": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ReviewRating" } @@ -290,10 +238,7 @@ ] }, "localizations": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "object", "additionalProperties": { @@ -325,10 +270,7 @@ "type": "string" }, "code": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "value": { "type": "integer", @@ -337,10 +279,7 @@ "maximum": 255 } }, - "required": [ - "explanation", - "value" - ] + "required": ["explanation", "value"] }, "DateT": { "type": "string" @@ -355,25 +294,17 @@ }, "details": { "description": "A human-readable string giving details about the source of the assertion data.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "actors": { "description": "A list of [`Actor`]s associated with this source.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/Actor" } } }, - "required": [ - "type" - ] + "required": ["type"] }, "Actor": { "description": "Identifies a person responsible for an action.", @@ -381,17 +312,11 @@ "properties": { "identifier": { "description": "An identifier for a human actor, used when the \"type\" is `humanEntry.identified`.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "credentials": { "description": "List of references to W3C Verifiable Credentials.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/HashedUri" } @@ -411,24 +336,15 @@ }, "name": { "description": "A free-text string representing a human-readable name for the region which might be used in a user interface.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "identifier": { "description": "A free-text string representing a machine-readable, unique to this assertion, identifier for the region.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "type": { "description": "A value from a controlled vocabulary such as or an entity-specific\nvalue (e.g., com.litware.newType) that represents the type of thing(s) depicted by a region.\n\nNote this field serializes/deserializes into the name `type`.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "role": { "description": "A value from our controlled vocabulary or an entity-specific value (e.g., com.litware.coolArea) that represents\nthe role of a region among other regions.", @@ -443,10 +359,7 @@ }, "description": { "description": "A free-text string.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "metadata": { "description": "Additional information about the asset.", @@ -460,9 +373,7 @@ ] } }, - "required": [ - "region" - ] + "required": ["region"] }, "Range": { "description": "A spatial, temporal, frame, or textual range describing the region of interest.", @@ -528,9 +439,7 @@ ] } }, - "required": [ - "type" - ] + "required": ["type"] }, "RangeType": { "description": "The type of range for the region of interest.", @@ -580,43 +489,27 @@ }, "width": { "description": "The width for rectangles or diameter for circles.\n\nThis field can be ignored for polygons.", - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "height": { "description": "The height of a rectnagle.\n\nThis field can be ignored for circles and polygons.", - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "inside": { "description": "If the range is inside the shape.\n\nThe default value is true.", - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] }, "vertices": { "description": "The vertices of the polygon.\n\nThis field can be ignored for rectangles and circles.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/Coordinate" } } }, - "required": [ - "type", - "unit", - "origin" - ] + "required": ["type", "unit", "origin"] }, "ShapeType": { "description": "The type of shape for the range.", @@ -668,10 +561,7 @@ "format": "double" } }, - "required": [ - "x", - "y" - ] + "required": ["x", "y"] }, "Time": { "description": "A temporal range representing a starting time to an ending time.", @@ -684,17 +574,11 @@ }, "start": { "description": "The start time or the start of the asset if not present.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "end": { "description": "The end time or the end of the asset if not present.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -714,18 +598,12 @@ "properties": { "start": { "description": "The start of the frame or the end of the asset if not present.\n\nThe first frame/page starts at 0.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "end": { "description": "The end of the frame inclusive or the end of the asset if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" } } @@ -742,9 +620,7 @@ } } }, - "required": [ - "selectors" - ] + "required": ["selectors"] }, "TextSelectorRange": { "description": "One or two [`TextSelector`][TextSelector] identifiying the range to select.", @@ -766,9 +642,7 @@ ] } }, - "required": [ - "selector" - ] + "required": ["selector"] }, "TextSelector": { "description": "Selects a range of text via a fragment identifier.\n\nThis is modeled after the W3C Web Annotation selector model.", @@ -780,24 +654,16 @@ }, "start": { "description": "The start character offset or the start of the fragment if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "end": { "description": "The end character offset or the end of the fragment if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" } }, - "required": [ - "fragment" - ] + "required": ["fragment"] }, "Item": { "description": "Description of the boundaries of an identified range.", @@ -812,10 +678,7 @@ "type": "string" } }, - "required": [ - "identifier", - "value" - ] + "required": ["identifier", "value"] }, "Role": { "description": "A role describing the region.", @@ -873,38 +736,23 @@ "properties": { "title": { "description": "A human-readable title, generally source filename.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "format": { "description": "The format of the source file as a MIME type.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "document_id": { "description": "Document ID from `xmpMM:DocumentID` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "instance_id": { "description": "Instance ID from `xmpMM:InstanceID` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "provenance": { "description": "URI from `dcterms:provenance` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "thumbnail": { "description": "A thumbnail image capturing the visual state at the time of import.\n\nA tuple of thumbnail MIME format (for example `image/jpeg`) and binary bits of the image.", @@ -919,10 +767,7 @@ }, "hash": { "description": "An optional hash of the asset to prevent duplicates.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "relationship": { "description": "Set to `ParentOf` if this is the parent ingredient.\n\nThere can only be one parent ingredient in the ingredients.", @@ -931,17 +776,11 @@ }, "active_manifest": { "description": "The active manifest label (if one exists).\n\nIf this ingredient has a [`ManifestStore`],\nthis will hold the label of the active [`Manifest`].\n\n[`Manifest`]: crate::Manifest\n[`ManifestStore`]: crate::ManifestStore", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "validation_status": { "description": "Validation status (Ingredient v1 & v2)", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ValidationStatus" } @@ -970,17 +809,11 @@ }, "description": { "description": "Additional description of the ingredient.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "informational_URI": { "description": "URI to an informational page about the ingredient or its data.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "metadata": { "description": "Any additional [`Metadata`] as defined in the C2PA spec.\n\n[`Metadata`]: crate::Metadata", @@ -995,10 +828,7 @@ }, "data_types": { "description": "Additional information about the data's type to the ingredient V2 structure.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssetType" } @@ -1016,16 +846,10 @@ }, "label": { "description": "The ingredient's label as assigned in the manifest.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "ocsp_responses": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ResourceRef" } @@ -1060,28 +884,17 @@ "type": "string" }, "url": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "explanation": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "success": { - "type": [ - "boolean", - "null" - ], + "type": ["boolean", "null"], "writeOnly": true } }, - "required": [ - "code" - ] + "required": ["code"] }, "ValidationResults": { "description": "A map of validation results for a manifest store.\n\nThe map contains the validation results for the active manifest and any ingredient deltas.\nIt is normal for there to be many", @@ -1100,10 +913,7 @@ }, "ingredientDeltas": { "description": "List of any changes/deltas between the current and previous validation results for each ingredient's\nmanifest. Present if the the ingredient is a C2PA asset.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/IngredientDeltaValidationResult" } @@ -1135,11 +945,7 @@ } } }, - "required": [ - "success", - "informational", - "failure" - ] + "required": ["success", "informational", "failure"] }, "IngredientDeltaValidationResult": { "description": "Represents any changes or deltas between the current and previous validation results for an ingredient's manifest.", @@ -1154,10 +960,7 @@ "$ref": "#/$defs/StatusCodes" } }, - "required": [ - "ingredientAssertionURI", - "validationDeltas" - ] + "required": ["ingredientAssertionURI", "validationDeltas"] }, "AssertionDefinition": { "description": "Defines an assertion that consists of a label that can be either\na C2PA-defined assertion label or a custom label in reverse domain format.", @@ -1187,26 +990,16 @@ "type": "boolean" } }, - "required": [ - "label", - "data" - ] + "required": ["label", "data"] }, "AssertionData": { "description": "This allows the assertion to be expressed as CBOR or JSON.\nThe default is CBOR unless you specify that an assertion should be JSON.", - "anyOf": [ - true - ] + "anyOf": [true] }, "ManifestAssertionKind": { "description": "Assertions in C2PA can be stored in several formats", "type": "string", - "enum": [ - "Cbor", - "Json", - "Binary", - "Uri" - ] + "enum": ["Cbor", "Json", "Binary", "Uri"] } } -} \ No newline at end of file +} diff --git a/static/schemas/Reader.schema.json b/static/schemas/Reader.schema.json index f5d62364..ace7aa0a 100644 --- a/static/schemas/Reader.schema.json +++ b/static/schemas/Reader.schema.json @@ -6,24 +6,19 @@ "properties": { "active_manifest": { "description": "A label for the active (most recent) manifest in the store", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "manifests": { "description": "A HashMap of Manifests", "type": "object", "additionalProperties": { "$ref": "#/$defs/Manifest" - } + }, + "default": {} }, "validation_status": { "description": "ValidationStatus generated when loading the ManifestStore from an asset", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ValidationStatus" } @@ -51,9 +46,6 @@ ] } }, - "required": [ - "manifests" - ], "$defs": { "Manifest": { "description": "A Manifest represents all the information in a c2pa manifest", @@ -61,51 +53,33 @@ "properties": { "vendor": { "description": "Optional prefix added to the generated Manifest label.\nThis is typically an internet domain name for the vendor (i.e. `adobe`).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "claim_generator": { "description": "A User Agent formatted string identifying the software/hardware/system produced this claim\nSpaces are not allowed in names, versions can be specified with product/1.0 syntax.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "claim_generator_info": { "description": "A list of claim generator info data identifying the software/hardware/system produced this claim.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ClaimGeneratorInfo" } }, "metadata": { "description": "A list of user metadata for this claim.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssertionMetadata" } }, "title": { "description": "A human-readable title, generally source filename.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "format": { "description": "The format of the source file as a MIME type.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "instance_id": { "description": "Instance ID from `xmpMM:InstanceID` in XMP metadata.", @@ -131,10 +105,7 @@ }, "credentials": { "description": "A List of verified credentials", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": true }, "assertions": { @@ -147,10 +118,7 @@ }, "redactions": { "description": "A list of redactions - URIs to a redacted assertions", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } @@ -167,17 +135,11 @@ ] }, "label": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "claim_version": { "description": "The version of the claim, parsed from the claim label.\n\nFor example:\n- `c2pa.claim.v2` -> 2\n- `c2pa.claim` -> 1", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint8", "minimum": 0, "maximum": 255 @@ -194,10 +156,7 @@ }, "version": { "description": "A human readable string of the product's version", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "icon": { "description": "hashed URI to the icon (either embedded or remote)", @@ -212,15 +171,10 @@ }, "operating_system": { "description": "A human readable string of the OS the claim generator is running on", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "name" - ], + "required": ["name"], "additionalProperties": true }, "UriOrResource": { @@ -247,33 +201,21 @@ }, "data_types": { "description": "More detailed data types as defined in the C2PA spec.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssetType" } }, "alg": { "description": "The algorithm used to hash the resource (if applicable).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hash": { "description": "The hash of the resource (if applicable).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "format", - "identifier" - ] + "required": ["format", "identifier"] }, "AssetType": { "type": "object", @@ -282,15 +224,10 @@ "type": "string" }, "version": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "type" - ] + "required": ["type"] }, "HashedUri": { "description": "A `HashedUri` provides a reference to content available within the same\nmanifest store.\n\nThis is described in [§8.3, URI References], of the C2PA Technical\nSpecification.\n\n[§8.3, URI References]: https://c2pa.org/specifications/specifications/2.1/specs/C2PA_Specification.html#_uri_references", @@ -302,10 +239,7 @@ }, "alg": { "description": "A string identifying the cryptographic hash algorithm used to compute\nthe hash", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hash": { "description": "Byte string containing the hash value", @@ -318,20 +252,14 @@ } } }, - "required": [ - "url", - "hash" - ] + "required": ["url", "hash"] }, "AssertionMetadata": { "description": "The AssertionMetadata structure can be used as part of other assertions or on its own to reference others", "type": "object", "properties": { "reviewRatings": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ReviewRating" } @@ -367,10 +295,7 @@ ] }, "localizations": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "object", "additionalProperties": { @@ -402,10 +327,7 @@ "type": "string" }, "code": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "value": { "type": "integer", @@ -414,10 +336,7 @@ "maximum": 255 } }, - "required": [ - "explanation", - "value" - ] + "required": ["explanation", "value"] }, "DateT": { "type": "string" @@ -432,25 +351,17 @@ }, "details": { "description": "A human-readable string giving details about the source of the assertion data.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "actors": { "description": "A list of [`Actor`]s associated with this source.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/Actor" } } }, - "required": [ - "type" - ] + "required": ["type"] }, "Actor": { "description": "Identifies a person responsible for an action.", @@ -458,17 +369,11 @@ "properties": { "identifier": { "description": "An identifier for a human actor, used when the \"type\" is `humanEntry.identified`.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "credentials": { "description": "List of references to W3C Verifiable Credentials.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/HashedUri" } @@ -488,24 +393,15 @@ }, "name": { "description": "A free-text string representing a human-readable name for the region which might be used in a user interface.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "identifier": { "description": "A free-text string representing a machine-readable, unique to this assertion, identifier for the region.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "type": { "description": "A value from a controlled vocabulary such as or an entity-specific\nvalue (e.g., com.litware.newType) that represents the type of thing(s) depicted by a region.\n\nNote this field serializes/deserializes into the name `type`.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "role": { "description": "A value from our controlled vocabulary or an entity-specific value (e.g., com.litware.coolArea) that represents\nthe role of a region among other regions.", @@ -520,10 +416,7 @@ }, "description": { "description": "A free-text string.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "metadata": { "description": "Additional information about the asset.", @@ -537,9 +430,7 @@ ] } }, - "required": [ - "region" - ] + "required": ["region"] }, "Range": { "description": "A spatial, temporal, frame, or textual range describing the region of interest.", @@ -605,9 +496,7 @@ ] } }, - "required": [ - "type" - ] + "required": ["type"] }, "RangeType": { "description": "The type of range for the region of interest.", @@ -657,43 +546,27 @@ }, "width": { "description": "The width for rectangles or diameter for circles.\n\nThis field can be ignored for polygons.", - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "height": { "description": "The height of a rectnagle.\n\nThis field can be ignored for circles and polygons.", - "type": [ - "number", - "null" - ], + "type": ["number", "null"], "format": "double" }, "inside": { "description": "If the range is inside the shape.\n\nThe default value is true.", - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] }, "vertices": { "description": "The vertices of the polygon.\n\nThis field can be ignored for rectangles and circles.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/Coordinate" } } }, - "required": [ - "type", - "unit", - "origin" - ] + "required": ["type", "unit", "origin"] }, "ShapeType": { "description": "The type of shape for the range.", @@ -745,10 +618,7 @@ "format": "double" } }, - "required": [ - "x", - "y" - ] + "required": ["x", "y"] }, "Time": { "description": "A temporal range representing a starting time to an ending time.", @@ -761,17 +631,11 @@ }, "start": { "description": "The start time or the start of the asset if not present.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "end": { "description": "The end time or the end of the asset if not present.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -791,18 +655,12 @@ "properties": { "start": { "description": "The start of the frame or the end of the asset if not present.\n\nThe first frame/page starts at 0.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "end": { "description": "The end of the frame inclusive or the end of the asset if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" } } @@ -819,9 +677,7 @@ } } }, - "required": [ - "selectors" - ] + "required": ["selectors"] }, "TextSelectorRange": { "description": "One or two [`TextSelector`][TextSelector] identifiying the range to select.", @@ -843,9 +699,7 @@ ] } }, - "required": [ - "selector" - ] + "required": ["selector"] }, "TextSelector": { "description": "Selects a range of text via a fragment identifier.\n\nThis is modeled after the W3C Web Annotation selector model.", @@ -857,24 +711,16 @@ }, "start": { "description": "The start character offset or the start of the fragment if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" }, "end": { "description": "The end character offset or the end of the fragment if not present.", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "int32" } }, - "required": [ - "fragment" - ] + "required": ["fragment"] }, "Item": { "description": "Description of the boundaries of an identified range.", @@ -889,10 +735,7 @@ "type": "string" } }, - "required": [ - "identifier", - "value" - ] + "required": ["identifier", "value"] }, "Role": { "description": "A role describing the region.", @@ -950,38 +793,23 @@ "properties": { "title": { "description": "A human-readable title, generally source filename.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "format": { "description": "The format of the source file as a MIME type.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "document_id": { "description": "Document ID from `xmpMM:DocumentID` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "instance_id": { "description": "Instance ID from `xmpMM:InstanceID` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "provenance": { "description": "URI from `dcterms:provenance` in XMP metadata.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "thumbnail": { "description": "A thumbnail image capturing the visual state at the time of import.\n\nA tuple of thumbnail MIME format (for example `image/jpeg`) and binary bits of the image.", @@ -996,10 +824,7 @@ }, "hash": { "description": "An optional hash of the asset to prevent duplicates.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "relationship": { "description": "Set to `ParentOf` if this is the parent ingredient.\n\nThere can only be one parent ingredient in the ingredients.", @@ -1008,17 +833,11 @@ }, "active_manifest": { "description": "The active manifest label (if one exists).\n\nIf this ingredient has a [`ManifestStore`],\nthis will hold the label of the active [`Manifest`].\n\n[`Manifest`]: crate::Manifest\n[`ManifestStore`]: crate::ManifestStore", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "validation_status": { "description": "Validation status (Ingredient v1 & v2)", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ValidationStatus" } @@ -1047,17 +866,11 @@ }, "description": { "description": "Additional description of the ingredient.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "informational_URI": { "description": "URI to an informational page about the ingredient or its data.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "metadata": { "description": "Any additional [`Metadata`] as defined in the C2PA spec.\n\n[`Metadata`]: crate::Metadata", @@ -1072,10 +885,7 @@ }, "data_types": { "description": "Additional information about the data's type to the ingredient V2 structure.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssetType" } @@ -1093,16 +903,10 @@ }, "label": { "description": "The ingredient's label as assigned in the manifest.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "ocsp_responses": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ResourceRef" } @@ -1137,28 +941,17 @@ "type": "string" }, "url": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "explanation": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "success": { - "type": [ - "boolean", - "null" - ], + "type": ["boolean", "null"], "writeOnly": true } }, - "required": [ - "code" - ] + "required": ["code"] }, "ValidationResults": { "description": "A map of validation results for a manifest store.\n\nThe map contains the validation results for the active manifest and any ingredient deltas.\nIt is normal for there to be many", @@ -1177,10 +970,7 @@ }, "ingredientDeltas": { "description": "List of any changes/deltas between the current and previous validation results for each ingredient's\nmanifest. Present if the the ingredient is a C2PA asset.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/IngredientDeltaValidationResult" } @@ -1212,11 +1002,7 @@ } } }, - "required": [ - "success", - "informational", - "failure" - ] + "required": ["success", "informational", "failure"] }, "IngredientDeltaValidationResult": { "description": "Represents any changes or deltas between the current and previous validation results for an ingredient's manifest.", @@ -1231,10 +1017,7 @@ "$ref": "#/$defs/StatusCodes" } }, - "required": [ - "ingredientAssertionURI", - "validationDeltas" - ] + "required": ["ingredientAssertionURI", "validationDeltas"] }, "ManifestAssertion": { "description": "A labeled container for an Assertion value in a Manifest", @@ -1250,10 +1033,7 @@ }, "instance": { "description": "There can be more than one assertion for any label", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint", "minimum": 0 }, @@ -1273,10 +1053,7 @@ "type": "boolean" } }, - "required": [ - "label", - "data" - ] + "required": ["label", "data"] }, "ManifestData": { "anyOf": [ @@ -1295,12 +1072,7 @@ "ManifestAssertionKind": { "description": "Assertions in C2PA can be stored in several formats", "type": "string", - "enum": [ - "Cbor", - "Json", - "Binary", - "Uri" - ] + "enum": ["Cbor", "Json", "Binary", "Uri"] }, "SignatureInfo": { "description": "Holds information about a signature", @@ -1319,38 +1091,23 @@ }, "issuer": { "description": "Human-readable issuing authority for this signature.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "common_name": { "description": "Human-readable for common name of this certificate.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "cert_serial_number": { "description": "The serial number of the certificate.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "time": { "description": "The time the signature was created.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "revocation_status": { "description": "Revocation status of the certificate.", - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] } } }, @@ -1415,4 +1172,4 @@ ] } } -} \ No newline at end of file +} diff --git a/static/schemas/Settings.schema.json b/static/schemas/Settings.schema.json index 00812c1e..22ec36b8 100644 --- a/static/schemas/Settings.schema.json +++ b/static/schemas/Settings.schema.json @@ -8,27 +8,91 @@ "description": "Version of the configuration.", "type": "integer", "format": "uint32", - "minimum": 0 + "minimum": 0, + "default": 1 }, "trust": { "description": "Settings for configuring the C2PA trust lists.", - "$ref": "#/$defs/Trust" + "$ref": "#/$defs/Trust", + "default": { + "verify_trust_list": true, + "user_anchors": null, + "trust_anchors": null, + "trust_config": null, + "allowed_list": null + } }, "cawg_trust": { "description": "Settings for configuring the CAWG trust lists.", - "$ref": "#/$defs/Trust" + "$ref": "#/$defs/Trust", + "default": { + "verify_trust_list": true, + "user_anchors": null, + "trust_anchors": null, + "trust_config": null, + "allowed_list": null + } }, "core": { "description": "Settings for configuring core features.", - "$ref": "#/$defs/Core" + "$ref": "#/$defs/Core", + "default": { + "merkle_tree_chunk_size_in_kb": null, + "merkle_tree_max_proofs": 5, + "backing_store_memory_threshold_in_mb": 512, + "decode_identity_assertions": true, + "allowed_network_hosts": null + } }, "verify": { "description": "Settings for configuring verification.", - "$ref": "#/$defs/Verify" + "$ref": "#/$defs/Verify", + "default": { + "verify_after_reading": true, + "verify_after_sign": false, + "verify_trust": true, + "verify_timestamp_trust": true, + "ocsp_fetch": false, + "remote_manifest_fetch": true, + "skip_ingredient_conflict_resolution": false, + "strict_v1_validation": false + } }, "builder": { "description": "Settings for configuring the [`Builder`].\n\n[`Builder`]: crate::Builder", - "$ref": "#/$defs/BuilderSettings" + "$ref": "#/$defs/BuilderSettings", + "default": { + "vendor": null, + "thumbnail": { + "enabled": true, + "ignore_errors": true, + "long_edge": 1024, + "prefer_smallest_format": true, + "quality": "medium" + }, + "actions": { + "actions": null, + "auto_created_action": { + "enabled": false + }, + "auto_opened_action": { + "enabled": false + }, + "auto_placed_action": { + "enabled": false + } + }, + "certificate_status_fetch": null, + "certificate_status_should_override": null, + "intent": null, + "created_assertion_labels": null, + "generate_c2pa_archive": true, + "auto_timestamp_assertion": { + "enabled": false, + "skip_existing": true, + "fetch_scope": "all" + } + } }, "signer": { "description": "Settings for configuring the base C2PA signer, accessible via [`Settings::signer`].", @@ -53,14 +117,6 @@ ] } }, - "required": [ - "version", - "trust", - "cawg_trust", - "core", - "verify", - "builder" - ], "$defs": { "Trust": { "description": "Settings to configure the trust list.", @@ -68,40 +124,30 @@ "properties": { "verify_trust_list": { "description": "Whether to verify certificates against the trust lists specified in [`Trust`]. This\noption is ONLY applicable to CAWG.\n\nThe default value is true.\n\n
\nVerifying trust is REQUIRED by the CAWG spec. This option should only be used for development or testing.\n
", - "type": "boolean" + "type": "boolean", + "default": true }, "user_anchors": { "description": "List of additional user-provided trust anchor root certificates as a PEM bundle.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"], + "default": null }, "trust_anchors": { "description": "List of default trust anchor root certificates as a PEM bundle.\n\nNormally this option contains the official C2PA-recognized trust anchors found here:\n", - "type": [ - "string", - "null" - ] + "type": ["string", "null"], + "default": null }, "trust_config": { "description": "List of allowed extended key usage (EKU) object identifiers (OID) that\ncertificates must have.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"], + "default": null }, "allowed_list": { "description": "List of explicitly allowed certificates as a PEM bundle.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"], + "default": null } - }, - "required": [ - "verify_trust_list" - ] + } }, "Core": { "description": "Settings to configure core features.", @@ -109,45 +155,39 @@ "properties": { "merkle_tree_chunk_size_in_kb": { "description": "Size of the [`BmffHash`] merkle tree chunks in kilobytes.\n\nThis option is associated with the [`MerkleMap::fixed_block_size`] field.\n\nSee more information in the spec here:\n\n\n[`MerkleMap::fixed_block_size`]: crate::assertions::MerkleMap::fixed_block_size\n[`BmffHash`]: crate::assertions::BmffHash", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint", - "minimum": 0 + "minimum": 0, + "default": null }, "merkle_tree_max_proofs": { "description": "Maximum number of proofs when validating or writing a [`BmffHash`] merkle tree.\n\nThis option defaults to 5.\n\nSee more information in the spec here:\n\n\n[`BmffHash`]: crate::assertions::BmffHash", "type": "integer", "format": "uint", - "minimum": 0 + "minimum": 0, + "default": 5 }, "backing_store_memory_threshold_in_mb": { "description": "Maximum amount of data in megabytes that will be loaded into memory before\nbeing stored in temporary files on the disk.\n\nThis option defaults to 512MB and can result in noticeable performance improvements.", "type": "integer", "format": "uint", - "minimum": 0 + "minimum": 0, + "default": 512 }, "decode_identity_assertions": { "description": "Whether to decode CAWG [`IdentityAssertion`]s during reading in the [`Reader`].\n\nThis option defaults to true.\n\n[`IdentityAssertion`]: crate::identity::IdentityAssertion\n[`Reader`]: crate::Reader", - "type": "boolean" + "type": "boolean", + "default": true }, "allowed_network_hosts": { "description": "
\nThe CAWG identity assertion does not currently respect this setting.\nSee issue #1645.\n
\n\nList of host patterns that are allowed for network requests.\n\nEach pattern may include:\n- A scheme (e.g. `https://` or `http://`)\n- A hostname or IP address (e.g. `contentauthenticity.org` or `192.0.2.1`)\n - The hostname may contain a single leading wildcard (e.g. `*.contentauthenticity.org`)\n- An optional port (e.g. `contentauthenticity.org:443` or `192.0.2.1:8080`)\n\nMatching is case-insensitive. A wildcard pattern such as `*.contentauthenticity.org` matches\n`sub.contentauthenticity.org`, but does not match `contentauthenticity.org` or `fakecontentauthenticity.org`.\nIf a scheme is present in the pattern, only URIs using the same scheme are considered a match. If the scheme\nis omitted, any scheme is allowed as long as the host matches.\n\nThe behavior is as follows:\n- `None` (default) no filtering enabled.\n- `Some(vec)` where `vec` is empty, all traffic is blocked.\n- `Some(vec)` with at least one pattern, filtering enabled for only those patterns.\n\n# Examples\n\nPattern: `*.contentauthenticity.org`\n- Does match:\n - `https://sub.contentauthenticity.org`\n - `http://api.contentauthenticity.org`\n- Does **not** match:\n - `https://contentauthenticity.org` (no subdomain)\n - `https://sub.fakecontentauthenticity.org` (different host)\n\nPattern: `http://192.0.2.1:8080`\n- Does match:\n - `http://192.0.2.1:8080`\n- Does **not** match:\n - `https://192.0.2.1:8080` (scheme mismatch)\n - `http://192.0.2.1` (port omitted)\n - `http://192.0.2.2:8080` (different IP address)\n\nThese settings are applied by the SDK's HTTP resolvers to restrict network requests.\nWhen network requests occur depends on the operations being performed (reading manifests,\nvalidating credentials, timestamping, etc.).", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/HostPattern" - } + }, + "default": null } - }, - "required": [ - "merkle_tree_max_proofs", - "backing_store_memory_threshold_in_mb", - "decode_identity_assertions" - ] + } }, "HostPattern": { "description": "A host/scheme pattern used to restrict network requests.\n\nEach pattern may include:\n- A scheme (e.g. `https://` or `http://`)\n- A hostname or IP address (e.g. `contentauthenticity.org` or `192.0.2.1`)\n - The hostname may contain a single leading wildcard (e.g. `*.contentauthenticity.org`)\n- An optional port (e.g. `contentauthenticity.org:443` or `192.0.2.1:8080`)\n\nMatching is case-insensitive. A wildcard pattern such as `*.contentauthenticity.org` matches\n`sub.contentauthenticity.org`, but does not match `contentauthenticity.org` or `fakecontentauthenticity.org`.\nIf a scheme is present in the pattern, only URIs using the same scheme are considered a match. If the scheme\nis omitted, any scheme is allowed as long as the host matches.\n\n# Examples\n\nPattern: `*.contentauthenticity.org`\n- Does match:\n - `https://sub.contentauthenticity.org`\n - `http://api.contentauthenticity.org`\n- Does **not** match:\n - `https://contentauthenticity.org` (no subdomain)\n - `https://sub.fakecontentauthenticity.org` (different host)\n\nPattern: `http://192.0.2.1:8080`\n- Does match:\n - `http://192.0.2.1:8080`\n- Does **not** match:\n - `https://192.0.2.1:8080` (scheme mismatch)\n - `http://192.0.2.1` (port omitted)\n - `http://192.0.2.2:8080` (different IP address)", @@ -159,47 +199,45 @@ "properties": { "verify_after_reading": { "description": "Whether to verify the manifest after reading in the [`Reader`].\n\nThe default value is true.\n\n
\nDisabling validation can improve reading performance, BUT it carries the risk of reading an invalid\nmanifest.\n
\n\n[`Reader`]: crate::Reader", - "type": "boolean" + "type": "boolean", + "default": true }, "verify_after_sign": { "description": "Whether to verify the manifest after signing in the [`Builder`].\n\nThe default value is true.\n\n
\nDisabling validation can improve signing performance, BUT it carries the risk of signing an invalid\nmanifest.\n
\n\n[`Builder`]: crate::Builder", - "type": "boolean" + "type": "boolean", + "default": false }, "verify_trust": { "description": "Whether to verify certificates against the trust lists specified in [`Trust`]. To configure\ntimestamp certificate verification, see [`Verify::verify_timestamp_trust`].\n\nThe default value is true.\n\n
\nVerifying trust is REQUIRED by the C2PA spec. This option should only be used for development or testing.\n
", - "type": "boolean" + "type": "boolean", + "default": true }, "verify_timestamp_trust": { "description": "Whether to verify the timestamp certificates against the trust lists specified in [`Trust`].\n\nThe default value is true.\n\n
\nVerifying timestamp trust is REQUIRED by the C2PA spec. This option should only be used for development or testing.\n
", - "type": "boolean" + "type": "boolean", + "default": true }, "ocsp_fetch": { "description": "Whether to fetch the certificates OCSP status during validation.\n\nRevocation status is checked in the following order:\n1. The OCSP staple stored in the COSE claim of the manifest\n2. Otherwise if `ocsp_fetch` is enabled, it fetches a new OCSP status\n3. Otherwise if `ocsp_fetch` is disabled, it checks `CertificateStatus` assertions\n\nThe default value is false.", - "type": "boolean" + "type": "boolean", + "default": false }, "remote_manifest_fetch": { "description": "Whether to fetch remote manifests in the following scenarios:\n- Constructing a [`Reader`]\n- Adding an [`Ingredient`] to the [`Builder`]\n\nThe default value is true.\n\n
\nThis setting is only applicable if the crate is compiled with the `fetch_remote_manifests` feature.\n
\n\n[`Reader`]: crate::Reader\n[`Ingredient`]: crate::Ingredient\n[`Builder`]: crate::Builder", - "type": "boolean" + "type": "boolean", + "default": true }, "skip_ingredient_conflict_resolution": { "description": "Whether to skip ingredient conflict resolution when multiple ingredients have the same\nmanifest identifier. This settings is only applicable for C2PA v2 validation.\n\nThe default value is false.\n\nSee more information in the spec here:\n", - "type": "boolean" + "type": "boolean", + "default": false }, "strict_v1_validation": { "description": "Whether to do strictly C2PA v1 validation or otherwise the latest validation.\n\nThe default value is false.", - "type": "boolean" + "type": "boolean", + "default": false } - }, - "required": [ - "verify_after_reading", - "verify_after_sign", - "verify_trust", - "verify_timestamp_trust", - "ocsp_fetch", - "remote_manifest_fetch", - "skip_ingredient_conflict_resolution", - "strict_v1_validation" - ] + } }, "BuilderSettings": { "description": "Settings for the [Builder][crate::Builder].", @@ -207,10 +245,7 @@ "properties": { "vendor": { "description": "The name of the vendor creating the content credential.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "claim_generator_info": { "description": "Claim generator info that is automatically added to the builder.\n\nNote that this information will prepend any claim generator info\nprovided explicitly to the builder.", @@ -244,10 +279,7 @@ }, "certificate_status_should_override": { "description": "Whether to only use [`CertificateStatus`] assertions to check certificate revocation status. If there\nis a stapled OCSP in the COSE claim of the manifest, it will be ignored. If [`Verify::ocsp_fetch`] is\nenabled, it will also be ignored.\n\nThe default value is false.\n\n[`CertificateStatus`]: crate::assertions::CertificateStatus\n[`Verify::ocsp_fetch`]: crate::settings::Verify::ocsp_fetch", - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] }, "intent": { "description": "The default [`BuilderIntent`] for the [`Builder`].\n\nSee [`BuilderIntent`] for more information.\n\n[`BuilderIntent`]: crate::BuilderIntent\n[`Builder`]: crate::Builder", @@ -262,31 +294,21 @@ }, "created_assertion_labels": { "description": "Assertions with a base label included in this list will be automatically marked as a created assertion.\nAssertions not in this list will be automatically marked as gathered.\n\nNote that the label should be a **base label**, not including the assertion version nor instance.\n\nSee more information on the difference between created vs gathered assertions in the spec here:\n", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } }, "generate_c2pa_archive": { "description": "Whether to generate a C2PA archive (instead of zip) when writing the manifest builder.\nNow always defaults to true - the ability to disable it will be removed in the future.", - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] }, "auto_timestamp_assertion": { "description": "Settings for configuring auto-generation of the [`TimeStamp`] assertion.\n\n[`TimeStamp`]: crate::assertions::TimeStamp", "$ref": "#/$defs/TimeStampSettings" } }, - "required": [ - "thumbnail", - "actions", - "auto_timestamp_assertion" - ] + "required": ["thumbnail", "actions", "auto_timestamp_assertion"] }, "ClaimGeneratorInfoSettings": { "description": "Settings for the claim generator info.", @@ -298,10 +320,7 @@ }, "version": { "description": "A human readable string of the product's version.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "icon": { "description": "Reference to an icon.", @@ -326,9 +345,7 @@ ] } }, - "required": [ - "name" - ], + "required": ["name"], "additionalProperties": true }, "ResourceRef": { @@ -345,33 +362,21 @@ }, "data_types": { "description": "More detailed data types as defined in the C2PA spec.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/AssetType" } }, "alg": { "description": "The algorithm used to hash the resource (if applicable).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hash": { "description": "The hash of the resource (if applicable).", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "format", - "identifier" - ] + "required": ["format", "identifier"] }, "AssetType": { "type": "object", @@ -380,15 +385,10 @@ "type": "string" }, "version": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } }, - "required": [ - "type" - ] + "required": ["type"] }, "ClaimGeneratorInfoOperatingSystem": { "anyOf": [ @@ -504,17 +504,11 @@ "properties": { "all_actions_included": { "description": "Whether or not to set the [Actions::all_actions_included][crate::assertions::Actions::all_actions_included]\nfield.", - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] }, "templates": { "description": "Templates to be added to the [Actions::templates][crate::assertions::Actions::templates] field.", - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "$ref": "#/$defs/ActionTemplateSettings" } @@ -559,10 +553,7 @@ }, "software_agent_index": { "description": "0-based index into the softwareAgents array", - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "format": "uint", "minimum": 0 }, @@ -590,23 +581,15 @@ }, "description": { "description": "Description of the template.", - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "template_parameters": { "description": "Additional parameters for the template", - "type": [ - "object", - "null" - ], + "type": ["object", "null"], "additionalProperties": true } }, - "required": [ - "action" - ] + "required": ["action"] }, "DigitalSourceType": { "description": "Description of the source of an asset.\n\nThe full list of possible digital source types are found below:\n\n", @@ -750,9 +733,7 @@ ] } }, - "required": [ - "enabled" - ] + "required": ["enabled"] }, "OcspFetchScope": { "description": "The scope of which manifests to fetch for OCSP.", @@ -780,9 +761,7 @@ "$ref": "#/$defs/DigitalSourceType" } }, - "required": [ - "create" - ], + "required": ["create"], "additionalProperties": false }, { @@ -814,11 +793,7 @@ "$ref": "#/$defs/TimeStampFetchScope" } }, - "required": [ - "enabled", - "skip_existing", - "fetch_scope" - ] + "required": ["enabled", "skip_existing", "fetch_scope"] }, "TimeStampFetchScope": { "description": "The scope of manifests to fetch timestamps for.\n\nSee [`TimeStampSettings`] for more information.", @@ -855,40 +830,25 @@ "type": "string" }, "tsa_url": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "referenced_assertions": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } }, "roles": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } } }, - "required": [ - "alg", - "sign_cert", - "private_key" - ] + "required": ["alg", "sign_cert", "private_key"] } }, - "required": [ - "local" - ], + "required": ["local"], "additionalProperties": false }, { @@ -908,40 +868,25 @@ "type": "string" }, "tsa_url": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "referenced_assertions": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } }, "roles": { - "type": [ - "array", - "null" - ], + "type": ["array", "null"], "items": { "type": "string" } } }, - "required": [ - "url", - "alg", - "sign_cert" - ] + "required": ["url", "alg", "sign_cert"] } }, - "required": [ - "remote" - ], + "required": ["remote"], "additionalProperties": false } ] @@ -987,4 +932,4 @@ ] } } -} \ No newline at end of file +}