diff --git a/src/Application/Import/ManifestNormalizer.php b/src/Application/Import/ManifestNormalizer.php index 17daab2..f2ce0ae 100644 --- a/src/Application/Import/ManifestNormalizer.php +++ b/src/Application/Import/ManifestNormalizer.php @@ -168,7 +168,12 @@ private function normalizeAlbumMeta(array $album, string $provider, array &$erro $this->setLicenseUrl($meta, MetadataKeys::ALBUM_LICENSE_URL, $this->firstString($license, ['url'], true, $errors, 'license URL'), $errors); $cover = isset($album['cover']) && is_array($album['cover']) ? $album['cover'] : []; - $this->setRemoteUrl($meta, MetadataKeys::ALBUM_REMOTE_COVER_URL, $this->firstString($cover, ['url'], true, $errors, 'remote cover URL'), $provider, $errors, 'remote cover URL'); + $coverProvider = $provider; + $coverSource = $this->sanitizer->sanitizeProvider($this->stringField($cover, 'source', true, $errors, 'cover.source')); + if ($coverSource !== '') { + $coverProvider = $coverSource; + } + $this->setRemoteUrl($meta, MetadataKeys::ALBUM_REMOTE_COVER_URL, $this->firstString($cover, ['url'], true, $errors, 'remote cover URL'), $coverProvider, $errors, 'remote cover URL'); $this->setText($meta, MetadataKeys::ALBUM_ARTIST_DISPLAY, $this->firstString($album, ['artist', 'artist_display'], true, $errors, 'artist')); $this->setText($meta, MetadataKeys::ALBUM_RELEASE_DATE, $this->sanitizer->sanitizeReleaseDate($this->firstString($album, ['release_date'], true, $errors, 'release date'))); diff --git a/tests/Unit/SingleReleaseManifestImporterTest.php b/tests/Unit/SingleReleaseManifestImporterTest.php index 59195d5..06453e8 100644 --- a/tests/Unit/SingleReleaseManifestImporterTest.php +++ b/tests/Unit/SingleReleaseManifestImporterTest.php @@ -582,6 +582,53 @@ public function testValidCoverCreatesAttachmentAndAssignsFeaturedImage(): void self::assertSame('TEST001:cover', get_post_meta($result->albumPostId, MetadataKeys::ALBUM_COVER_EXTERNAL_ID, true)); } + public function testInternetArchiveAlbumAllowsDirectCoverSourceForSafeHttpsCover(): void + { + $manifest = $this->manifestWithSideloadCover(); + $manifest["album"]["source_provider"] = "internet_archive"; + $manifest["album"]["catalog_key"] = "internet_archive"; + $manifest["album"]["internet_archive_url"] = "https://archive.org/details/test001"; + $manifest["album"]["internet_archive_identifier"] = "test001"; + $manifest["album"]["cover"]["source"] = "direct"; + $manifest["album"]["cover"]["url"] = "https://lab.m-d-k.cc/wp-content/uploads/campwp-smoke/mdk148-cover.png"; + $manifest["album"]["cover"]["filename"] = "mdk148-cover.png"; + $sideloader = new FakeCoverSideloader("sha256:" . str_repeat("1", 64)); + + $result = $this->importer($sideloader)->importArray($manifest); + + self::assertTrue($result->isSuccess(), implode(", ", $result->errors)); + self::assertSame("created", $result->coverResult?->action); + self::assertSame("https://lab.m-d-k.cc/wp-content/uploads/campwp-smoke/mdk148-cover.png", get_post_meta($result->albumPostId, MetadataKeys::ALBUM_REMOTE_COVER_URL, true)); + self::assertSame("direct", get_post_meta($result->albumPostId, MetadataKeys::ALBUM_COVER_SOURCE, true)); + } + + public function testInternetArchiveCoverSourceStillRejectsNonArchiveCoverUrl(): void + { + $manifest = $this->manifestWithSideloadCover(); + $manifest["album"]["source_provider"] = "internet_archive"; + $manifest["album"]["catalog_key"] = "internet_archive"; + $manifest["album"]["internet_archive_url"] = "https://archive.org/details/test001"; + $manifest["album"]["internet_archive_identifier"] = "test001"; + $manifest["album"]["cover"]["source"] = "internet_archive"; + $manifest["album"]["cover"]["url"] = "https://lab.m-d-k.cc/wp-content/uploads/campwp-smoke/mdk148-cover.png"; + $manifest["album"]["cover"]["filename"] = "mdk148-cover.png"; + + $result = $this->importer(new FakeCoverSideloader())->importArray($manifest); + + self::assertFalse($result->isSuccess()); + self::assertContains("remote cover URL is unsafe or unsupported.", $result->errors); + self::assertContains("cover.url is unsafe or unsupported.", $result->errors); + self::assertSame([], $GLOBALS["campwp_test_posts"]); + } + + public function testMdkInternetArchiveCoverFixtureStillPassesValidation(): void + { + $result = $this->importer(new FakeCoverSideloader("sha256:" . str_repeat("2", 64)))->importArray($this->mdkManifest(), true); + + self::assertTrue($result->isSuccess(), implode(", ", $result->errors)); + self::assertSame("created", $result->coverResult?->action); + } + public function testRepeatedCoverImportIsUnchangedAndDoesNotDownloadAgain(): void { $manifest = $this->manifestWithSideloadCover();