| // Copyright 2026 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // | |
| #include "claim/manifest_store_view.h" | |
| #include <optional> | |
| #include <utility> | |
| #include "absl/status/status.h" | |
| #include "absl/status/status_macros.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/string_view.h" | |
| #include "constants/labels.h" | |
| #include "cose/sig_structure.h" | |
| #include "jumbf/box.h" | |
| #include "jumbf/parse.h" | |
| namespace credentio { | |
| namespace { | |
| bool IsManifestStore(const jumbf::SuperBox& superbox) { | |
| return superbox.description.type_uuid == kManifestStoreUuid && | |
| superbox.description.label == kManifestStoreLabel; | |
| } | |
| bool IsManifest(const jumbf::SuperBox& superbox) { | |
| return superbox.description.type_uuid == kStandardManifestUuid || | |
| superbox.description.type_uuid == kUpdateManifestUuid || | |
| superbox.description.type_uuid == kTimestampManifestUuid || | |
| superbox.description.type_uuid == kCompressedManifestUuid; | |
| } | |
| bool IsClaimSignature(const jumbf::SuperBox& superbox) { | |
| return superbox.description.type_uuid == kClaimSignatureUuid && | |
| superbox.description.label == kClaimSignatureLabel; | |
| } | |
| } // namespace | |
| absl::StatusOr<ManifestStoreView> ManifestStoreView::Create( | |
| absl::string_view manifest_store) { | |
| ABSL_ASSIGN_OR_RETURN( | |
| auto super_box_res, | |
| jumbf::ConsumeSuperBox(&manifest_store, /*recursion_limit=*/4)); | |
| jumbf::SuperBox super_box = std::move(super_box_res); | |
| if (!IsManifestStore(super_box)) { | |
| return absl::InvalidArgumentError("No C2PA manifest store"); | |
| } | |
| return ManifestStoreView(std::move(super_box)); | |
| } | |
| absl::StatusOr<ManifestView> ManifestStoreView::GetActiveManifest() const { | |
| const jumbf::SuperBox* active_manifest = nullptr; | |
| for (const auto& box : superbox_.contents) { | |
| if (box.Holds<jumbf::SuperBox>()) { | |
| const auto& superbox = box.Get<jumbf::SuperBox>(); | |
| if (IsManifest(superbox)) { | |
| active_manifest = &superbox; | |
| } | |
| } | |
| } | |
| if (active_manifest == nullptr) { | |
| return absl::InvalidArgumentError("No active manifest found"); | |
| } | |
| return ManifestView::Create(*active_manifest); | |
| } | |
| absl::StatusOr<ManifestView> ManifestView::Create(jumbf::SuperBox superbox) { | |
| if (!IsManifest(superbox)) { | |
| return absl::InvalidArgumentError("Not a manifest box"); | |
| } | |
| if (superbox.description.type_uuid == kCompressedManifestUuid) { | |
| return absl::InvalidArgumentError("Compressed manifests are not supported"); | |
| } | |
| return ManifestView(std::move(superbox)); | |
| } | |
| absl::StatusOr<ClaimSignatureView> ManifestView::GetClaimSignature() const { | |
| std::optional<jumbf::SuperBox> claim_signature_superbox = std::nullopt; | |
| for (const auto& content : superbox_.contents) { | |
| if (content.Holds<jumbf::SuperBox>() && | |
| IsClaimSignature(content.Get<jumbf::SuperBox>())) { | |
| claim_signature_superbox = content.Get<jumbf::SuperBox>(); | |
| break; | |
| } | |
| } | |
| if (!claim_signature_superbox.has_value()) { | |
| return absl::InvalidArgumentError( | |
| "No claim signature found in the manifest"); | |
| } | |
| return ClaimSignatureView::Create(claim_signature_superbox.value()); | |
| } | |
| absl::string_view ManifestView::label() const { | |
| return superbox_.description.label.value_or(""); | |
| } | |
| absl::StatusOr<ClaimSignatureView> ClaimSignatureView::Create( | |
| jumbf::SuperBox superbox) { | |
| if (!IsClaimSignature(superbox)) { | |
| return absl::InvalidArgumentError("Not a claim signature box"); | |
| } | |
| return ClaimSignatureView(std::move(superbox)); | |
| } | |
| absl::StatusOr<absl::string_view> ClaimSignatureView::GetPayload() const { | |
| if (superbox_.contents.size() != 1 || | |
| !superbox_.contents[0].Holds<jumbf::CborBox>()) { | |
| return absl::InvalidArgumentError("Invalid claim signature box"); | |
| } | |
| return superbox_.contents[0].Get<jumbf::CborBox>().payload; | |
| } | |
| absl::StatusOr<CoseSign1TaggedStructure> ClaimSignatureView::GetStruct() const { | |
| ABSL_ASSIGN_OR_RETURN(auto payload_res, GetPayload()); | |
| return DecodeCoseSign1TaggedStructure(payload_res); | |
| } | |
| } // namespace credentio |