Skip to content

Commit dd95ad9

Browse files
committed
🎉 Howdy
0 parents  commit dd95ad9

33 files changed

+4330
-0
lines changed

.editorconfig

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
insert_final_newline = true
7+
trim_trailing_whitespace = true
8+
indent_style = space
9+
indent_size = 4
10+
11+
[*.{yml,yaml}]
12+
indent_size = 2
13+
14+
[*.json]
15+
indent_size = 2
16+
17+
[*.md]
18+
trim_trailing_whitespace = false
19+
20+
[composer.json]
21+
indent_size = 4
22+
23+
[*.js]
24+
indent_size = 2

.gitattributes

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto
3+
4+
# Source code files
5+
*.php text eol=lf
6+
*.js text eol=lf
7+
*.json text eol=lf
8+
*.yml text eol=lf
9+
*.yaml text eol=lf
10+
*.xml text eol=lf
11+
*.md text eol=lf
12+
*.txt text eol=lf
13+
14+
# Config files
15+
.gitignore text eol=lf
16+
.gitattributes text eol=lf
17+
composer.json text eol=lf
18+
composer.lock text eol=lf
19+
*.config.js text eol=lf
20+
21+
# Test files
22+
tests/** text eol=lf
23+
24+
# Exclude from archives
25+
/.github/ export-ignore
26+
/.wp-env.json export-ignore
27+
/tests/ export-ignore
28+
/phpunit.xml export-ignore
29+
/playwright.config.js export-ignore
30+
/pint.json export-ignore
31+
/scoper.inc.php export-ignore
32+
/DEVELOPMENT_PLAN.md export-ignore
33+
/coverage/ export-ignore
34+
/.phpunit.cache/ export-ignore
35+
/test-results/ export-ignore
36+
37+
# Binary files
38+
*.svg binary
39+
*.png binary
40+
*.jpg binary
41+
*.jpeg binary
42+
*.gif binary
43+
*.ico binary
44+
*.pdf binary

.github/workflows/tests.yml

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
lint:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Setup PHP
18+
uses: shivammathur/setup-php@v2
19+
with:
20+
php-version: 8.2
21+
coverage: none
22+
23+
- name: Cache Composer dependencies
24+
uses: actions/cache@v3
25+
with:
26+
path: /tmp/composer-cache
27+
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
28+
29+
- name: Install dependencies
30+
run: composer install --prefer-dist --no-interaction --no-progress
31+
32+
- name: Run linting
33+
run: composer lint-check
34+
35+
unit-tests:
36+
runs-on: ubuntu-latest
37+
38+
strategy:
39+
matrix:
40+
php-version: [8.2, 8.3]
41+
42+
steps:
43+
- name: Checkout code
44+
uses: actions/checkout@v4
45+
46+
- name: Setup PHP
47+
uses: shivammathur/setup-php@v2
48+
with:
49+
php-version: ${{ matrix.php-version }}
50+
coverage: none
51+
52+
- name: Cache Composer dependencies
53+
uses: actions/cache@v3
54+
with:
55+
path: /tmp/composer-cache
56+
key: ${{ runner.os }}-${{ hashFiles('**/composer.lock') }}
57+
58+
- name: Install dependencies
59+
run: composer install --prefer-dist --no-interaction --no-progress
60+
61+
- name: Run PHPUnit tests
62+
run: composer test
63+
64+
integration-tests:
65+
runs-on: ubuntu-latest
66+
67+
steps:
68+
- name: Checkout code
69+
uses: actions/checkout@v4
70+
71+
- name: Setup PHP
72+
uses: shivammathur/setup-php@v2
73+
with:
74+
php-version: 8.2
75+
coverage: none
76+
77+
- name: Setup Node.js
78+
uses: actions/setup-node@v4
79+
with:
80+
node-version: '18'
81+
82+
- name: Install dependencies
83+
run: composer install --prefer-dist --no-interaction --no-progress
84+
85+
- name: Install wp-env
86+
run: npm install -g @wordpress/env
87+
88+
- name: Start WordPress environment
89+
run: npx wp-env start
90+
91+
- name: Wait for WordPress
92+
run: |
93+
timeout 60 bash -c 'until curl -f http://localhost:8889 > /dev/null 2>&1; do sleep 2; done'
94+
95+
- name: Run WP-CLI integration tests
96+
run: composer test-wp-cli
97+
98+
e2e-tests:
99+
runs-on: ubuntu-latest
100+
101+
steps:
102+
- name: Checkout code
103+
uses: actions/checkout@v4
104+
105+
- name: Setup PHP
106+
uses: shivammathur/setup-php@v2
107+
with:
108+
php-version: 8.2
109+
coverage: none
110+
111+
- name: Setup Node.js
112+
uses: actions/setup-node@v4
113+
with:
114+
node-version: '18'
115+
116+
- name: Install dependencies
117+
run: composer install --prefer-dist --no-interaction --no-progress
118+
119+
- name: Install wp-env and Playwright
120+
run: |
121+
npm install -g @wordpress/env
122+
npm install @playwright/test
123+
124+
- name: Install Playwright browsers
125+
run: npx playwright install chromium
126+
127+
- name: Start WordPress environment
128+
run: npx wp-env start
129+
130+
- name: Wait for WordPress
131+
run: |
132+
timeout 60 bash -c 'until curl -f http://localhost:8889 > /dev/null 2>&1; do sleep 2; done'
133+
134+
- name: Run E2E tests
135+
run: composer test-e2e
136+
137+
- name: Upload E2E test results
138+
uses: actions/upload-artifact@v4
139+
if: failure()
140+
with:
141+
name: playwright-report
142+
path: test-results/
143+
retention-days: 7

.gitignore

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Dependencies
2+
/vendor/
3+
/node_modules/
4+
5+
# Build artifacts
6+
/build/
7+
8+
# Testing
9+
/coverage/
10+
/.phpunit.cache/
11+
/test-results/
12+
/playwright-report/
13+
14+
# IDE
15+
/.vscode/
16+
/.idea/
17+
*.swp
18+
*.swo
19+
20+
# OS
21+
.DS_Store
22+
Thumbs.db
23+
24+
# WordPress
25+
/.wp-env.override.json
26+
27+
# Temporary files
28+
*.log
29+
*.tmp
30+
*.temp
31+
32+
# Composer
33+
/composer.phar

.wp-env.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"core": "WordPress/WordPress",
3+
"phpVersion": "8.2",
4+
"plugins": [
5+
"."
6+
],
7+
"config": {
8+
"SCRIPT_DEBUG": true,
9+
"WP_DEBUG": true,
10+
"WP_DEBUG_LOG": true,
11+
"WP_DEBUG_DISPLAY": false
12+
}
13+
}

LICENSE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Roots Software LLC
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<p align="center">
2+
<a href="https://packagist.org/packages/roots/allow-svg"><img alt="Packagist Downloads" src="https://img.shields.io/packagist/dt/roots/allow-svg?label=downloads&colorB=2b3072&colorA=525ddc&style=flat-square"></a>
3+
<a href="https://github.com/roots/allow-svg/actions/workflows/tests.yml"><img alt="Build Status" src="https://img.shields.io/github/actions/workflow/status/roots/allow-svg/tests.yml?branch=main&logo=github&label=CI&style=flat-square"></a>
4+
<a href="https://bsky.app/profile/roots.io"><img alt="Follow roots.io on Bluesky" src="https://img.shields.io/badge/[email protected]?logo=bluesky&style=flat-square"></a>
5+
</p>
6+
7+
# Allow SVG
8+
9+
A WordPress plugin that enables SVG uploads with validation to block malicious files.
10+
11+
> WordPress still lacks native SVG support after [12+ years of discussion](https://core.trac.wordpress.org/ticket/24251)
12+
13+
## Features
14+
15+
-**SVG Upload Support** — Enables `.svg` uploads in the WordPress media library
16+
- 🔒 **Security-First Validation** — Detects and rejects SVG files containing potentially harmful content
17+
- 🖼️ **Media Library Integration** — SVGs display inline like standard images
18+
- 🧩 **Zero Dependencies** — No external libraries or frameworks
19+
- ⚙️ **Zero Configuration** — No settings or admin bloat
20+
21+
## Requirements
22+
23+
- PHP 8.2 or higher
24+
- WordPress 5.9 or higher
25+
26+
## Installation
27+
28+
### via Composer
29+
30+
```bash
31+
composer require roots/allow-svg
32+
```
33+
34+
<details>
35+
<summary>Install as a mu-plugin</summary>
36+
37+
If you are using [Bedrock](https://roots.io/bedrock/), you can install this as a must-use plugin by modifying your `composer.json` to install the package to the `mu-plugins` directory.
38+
39+
```json
40+
{
41+
"extra": {
42+
"installer-paths": {
43+
"web/app/mu-plugins/{$name}/": [
44+
"type:wordpress-muplugin",
45+
"roots/allow-svg"
46+
]
47+
}
48+
}
49+
}
50+
```
51+
52+
</details>
53+
54+
### Manual
55+
56+
1. Download `allow-svg.php`
57+
2. Place in `wp-content/plugins/allow-svg/`
58+
3. Activate via wp-admin or WP-CLI
59+
60+
## Usage
61+
62+
Once activated, the plugin automatically:
63+
64+
1. Enables SVG uploads through the Media Library or block editor
65+
2. Performs strict validation on all SVG files
66+
3. Rejects malicious files with clear error messages
67+
4. Accepts clean, standards-compliant SVGs as-is
68+
69+
No configuration required.
70+
71+
## Security
72+
73+
This plugin uses a **deny-first approach**: it doesn't attempt to sanitize SVGs, it rejects files that appear unsafe.
74+
75+
### Accepts:
76+
77+
- Basic SVG shapes, paths, text, and inline styles
78+
- ViewBox and standard attributes
79+
80+
### Rejects:
81+
82+
- `<script>` tags or inline JavaScript
83+
- Event handlers like `onclick`, `onload`, etc.
84+
- External references (`href`, `xlink:href`, `iframe`, `object`, `embed`)
85+
- CSS expressions and `@import` rules
86+
- Data URLs containing script or HTML content
87+
88+
### XML Hardening:
89+
90+
- **XXE Protection** — Blocks `<!DOCTYPE>` and external entity declarations
91+
- **Entity Expansion Limits** — Rejects suspicious `&entity;` usage
92+
- Uses `DOMDocument` with external entities disabled
93+
94+
## Sponsors
95+
96+
Allow SVG is an open source project and completely free to use. If you've benefited from our projects and would like to support our future endeavors, [please consider sponsoring us](https://github.com/sponsors/roots).
97+
98+
## Support
99+
100+
- GitHub Issues: https://github.com/roots/allow-svg/issues
101+
- Roots Discourse: https://discourse.roots.io/

0 commit comments

Comments
 (0)