Merge pull request 'Fix Decap image filename validation' (#2) from review/decap-image-validation into main
Reviewed-on: SloanOps/3031023-xyz#2
This commit is contained in:
@@ -156,6 +156,12 @@ not accept executables, archives, HTML, scripts, or SVG uploads. Asset rights,
|
||||
alt text, crop, dimensions, and optimization remain operator review items even
|
||||
when the CMS accepts an upload.
|
||||
|
||||
Decap's image widget applies its field `pattern` to the selected file's base
|
||||
name, not to the repository-relative media path. Keep that UI pattern limited
|
||||
to the approved raster filename extensions; enforce the full
|
||||
`public/images/uploads` path separately in the schema, verifier, and Gitea
|
||||
branch rules below.
|
||||
|
||||
The media gallery lists only `public/images/uploads`, so the pilot seeds that
|
||||
directory with the images referenced by CMS-controlled fields. Removing an
|
||||
image from content clears the field and uses the page's text-only or initials
|
||||
|
||||
@@ -144,7 +144,7 @@ collections:
|
||||
required: false
|
||||
choose_url: false
|
||||
allow_multiple: false
|
||||
pattern: ['^/images/uploads/[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
pattern: ['^[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
media_library:
|
||||
config:
|
||||
max_file_size: 512000
|
||||
@@ -181,7 +181,7 @@ collections:
|
||||
required: false
|
||||
choose_url: false
|
||||
allow_multiple: false
|
||||
pattern: ['^/images/uploads/[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
pattern: ['^[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
media_library:
|
||||
config: { max_file_size: 512000, multiple: false }
|
||||
- label: Home hero image description
|
||||
@@ -194,7 +194,7 @@ collections:
|
||||
required: false
|
||||
choose_url: false
|
||||
allow_multiple: false
|
||||
pattern: ['^/images/uploads/[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
pattern: ['^[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
media_library:
|
||||
config: { max_file_size: 512000, multiple: false }
|
||||
- label: Home story image description
|
||||
@@ -207,7 +207,7 @@ collections:
|
||||
required: false
|
||||
choose_url: false
|
||||
allow_multiple: false
|
||||
pattern: ['^/images/uploads/[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
pattern: ['^[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
media_library:
|
||||
config: { max_file_size: 512000, multiple: false }
|
||||
- label: About hero image description
|
||||
@@ -220,7 +220,7 @@ collections:
|
||||
required: false
|
||||
choose_url: false
|
||||
allow_multiple: false
|
||||
pattern: ['^/images/uploads/[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
pattern: ['^[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
media_library:
|
||||
config: { max_file_size: 512000, multiple: false }
|
||||
- label: About story image description
|
||||
@@ -233,7 +233,7 @@ collections:
|
||||
required: false
|
||||
choose_url: false
|
||||
allow_multiple: false
|
||||
pattern: ['^/images/uploads/[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
pattern: ['^[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
media_library:
|
||||
config: { max_file_size: 512000, multiple: false }
|
||||
- label: Services hero image description
|
||||
@@ -246,7 +246,7 @@ collections:
|
||||
required: false
|
||||
choose_url: false
|
||||
allow_multiple: false
|
||||
pattern: ['^/images/uploads/[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
pattern: ['^[A-Za-z0-9][A-Za-z0-9._-]*\.(?:jpe?g|png|webp|avif)$', 'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.']
|
||||
media_library:
|
||||
config: { max_file_size: 512000, multiple: false }
|
||||
- label: Contact hero image description
|
||||
|
||||
@@ -45,7 +45,7 @@ const markdownField = {
|
||||
editor_components: [],
|
||||
};
|
||||
const cmsImagePattern = [
|
||||
'^/images/uploads/[A-Za-z0-9][A-Za-z0-9._-]*\\.(?:jpe?g|png|webp|avif)$',
|
||||
'^[A-Za-z0-9][A-Za-z0-9._-]*\\.(?:jpe?g|png|webp|avif)$',
|
||||
'Choose an approved JPG, PNG, WebP, or AVIF upload. SVG and general files are not allowed.',
|
||||
];
|
||||
const optionalImageField = {
|
||||
@@ -160,6 +160,8 @@ allFields.forEach(visitField);
|
||||
const imageFields = allFields.filter(({ widget }) => widget === 'image');
|
||||
assert(imageFields.length === 7, 'Only the team image and six fixed page-image fields may expose media selection.');
|
||||
for (const field of imageFields) expectSubset(field, optionalImageField, `image field ${field.name}`);
|
||||
assert(new RegExp(cmsImagePattern[0]).test('example-photo.jpg'), 'Image widget validation must accept the filename Decap passes to field patterns.');
|
||||
assert(!new RegExp(cmsImagePattern[0]).test('example-photo.svg'), 'Image widget validation must reject SVG filenames.');
|
||||
|
||||
const schema = await readFile('src/content.config.ts', 'utf8');
|
||||
for (const fragment of [
|
||||
|
||||
Reference in New Issue
Block a user