mirror of
https://github.com/myronblair/tomtomgames
synced 2026-07-27 17:02:27 -05:00
674ec71682
Refund feature: token_purchases had no way to refund a completed Square payment - the existing resolve_purchase action only approves/rejects manual (Zelle etc) payments still in pending status. Adds a real refund_purchase action (api/admin.php) that calls Squares actual Refunds API via a new SquarePayment::refund() method, updates status to the new refunded enum value, logs the refund ID, and claws back the tokens credited on purchase (clamped at 0 if the customer already spent some, reported back as a shortfall so staff know). UI: admin/index.php shows a Refund button on completed card purchases with a square_payment_id. Tested in sandbox: full refund with full token clawback, and a shortfall scenario (user already spent below the credited amount) to confirm clamping works correctly rather than going negative. Also committing two earlier pending fixes from this session that were never committed: .htaccess .py/!install!! blocking hardening and moving bump_version.PHPs BUMP_KEY out of the web-reachable file into includes/config.php.
125 lines
5.7 KiB
ApacheConf
125 lines
5.7 KiB
ApacheConf
# ══════════════════════════════════════════════════════════
|
|
# TomTomGames Security Configuration
|
|
# ══════════════════════════════════════════════════════════
|
|
|
|
Options -Indexes -Includes
|
|
ServerSignature Off
|
|
|
|
# ── Block all sensitive file types ───────────────────────
|
|
<FilesMatch "\.(sql|env|log|sh|md|git|bak|backup|old|orig|tmp|swp|cfg|ini|conf|yaml|yml|json.bak)$">
|
|
Order allow,deny
|
|
Deny from all
|
|
</FilesMatch>
|
|
|
|
# ── Block direct access to sensitive PHP files ───────────
|
|
<FilesMatch "^(phpcheck|test|test_mail|test_login|sgtest|install|config|db|auth|mailer|square|smtp)\.php$">
|
|
Order allow,deny
|
|
Deny from all
|
|
</FilesMatch>
|
|
|
|
# ── Block access to includes and vendor folders ──────────
|
|
<IfModule mod_rewrite.c>
|
|
RewriteEngine On
|
|
RewriteRule ^includes/ - [F,L]
|
|
RewriteRule ^vendor/ - [F,L]
|
|
RewriteRule ^mail_queue/ - [F,L]
|
|
RewriteRule ^\.git/ - [F,L]
|
|
|
|
# Block sensitive file extensions anywhere in the tree — the
|
|
# <FilesMatch>/Order,Deny block above is not honored by this
|
|
# OpenLiteSpeed vhost (confirmed: db/schema.sql was still
|
|
# served 200 despite that rule), so enforce via RewriteRule,
|
|
# the mechanism proven to work here (.git/, vendor/ etc. above).
|
|
RewriteRule \.(sql|env|log|sh|bak|backup|old|orig|tmp|swp|cfg|ini|conf|yaml|yml)$ - [F,L]
|
|
</IfModule>
|
|
|
|
# ── Block common attack vectors ──────────────────────────
|
|
<IfModule mod_rewrite.c>
|
|
RewriteEngine On
|
|
|
|
# Block SQL injection attempts in query strings
|
|
RewriteCond %{QUERY_STRING} (union|select|insert|drop|delete|update|cast|exec|declare|char|convert|truncate).*= [NC,OR]
|
|
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
|
|
RewriteCond %{QUERY_STRING} \.\./\.\. [NC,OR]
|
|
RewriteCond %{QUERY_STRING} (javascript|vbscript|expression|applet|meta|xml|blink|link|iframe|input|embed|script|object|marquee) [NC]
|
|
RewriteRule .* - [F,L]
|
|
|
|
# Block base64 encoded attacks
|
|
RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [NC,OR]
|
|
RewriteCond %{QUERY_STRING} base64_(en|de)code[^(]*\([^)]*\) [NC]
|
|
RewriteRule .* - [F,L]
|
|
|
|
# Block common exploit scanners and bad bots
|
|
RewriteCond %{HTTP_USER_AGENT} (nikto|sqlmap|havij|nessus|masscan|zgrab|python-requests/2\.6|libwww-perl|wget|curl\/7\.[0-4]) [NC]
|
|
RewriteRule .* - [F,L]
|
|
</IfModule>
|
|
|
|
# ── Block access to WordPress paths (scanners look for these) ──
|
|
<IfModule mod_rewrite.c>
|
|
RewriteRule ^wp-admin - [F,L]
|
|
RewriteRule ^wp-login - [F,L]
|
|
RewriteRule ^xmlrpc - [F,L]
|
|
RewriteRule ^\.env - [F,L]
|
|
RewriteRule ^composer\. - [F,L]
|
|
</IfModule>
|
|
|
|
# ── Security Headers ──────────────────────────────────────
|
|
<IfModule mod_headers.c>
|
|
# Prevent MIME type sniffing
|
|
Header always set X-Content-Type-Options "nosniff"
|
|
|
|
# Prevent clickjacking
|
|
Header always set X-Frame-Options "DENY"
|
|
|
|
# XSS protection
|
|
Header always set X-XSS-Protection "1; mode=block"
|
|
|
|
# Referrer policy
|
|
Header always set Referrer-Policy "strict-origin-when-cross-origin"
|
|
|
|
# Permissions policy — disable dangerous browser features
|
|
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), gyroscope=()"
|
|
|
|
# Content Security Policy
|
|
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://web.squarecdn.com https://sandbox.web.squarecdn.com https://js.squareup.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' data: https://fonts.gstatic.com; img-src 'self' data: blob: https:; connect-src 'self' https: wss:; frame-src 'none'; object-src 'none'"
|
|
|
|
# Strict Transport Security — force HTTPS for 1 year
|
|
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
|
|
# Remove server info headers
|
|
Header unset Server
|
|
Header unset X-Powered-By
|
|
</IfModule>
|
|
|
|
# ── Canonical HTTPS + non-www redirect ───────────────────
|
|
<IfModule mod_rewrite.c>
|
|
RewriteEngine On
|
|
RewriteCond %{HTTPS} off
|
|
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
|
|
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
|
|
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
|
|
</IfModule>
|
|
|
|
# ── Block PHP execution in uploads folder (if it exists) ─
|
|
<IfModule mod_rewrite.c>
|
|
RewriteRule ^uploads/.*\.php$ - [F,L]
|
|
</IfModule>
|
|
|
|
# ── Gzip compression ──────────────────────────────────────
|
|
<IfModule mod_deflate.c>
|
|
AddOutputFilterByType DEFLATE text/html text/css text/javascript application/javascript application/json image/svg+xml
|
|
</IfModule>
|
|
|
|
# ── Browser caching ───────────────────────────────────────
|
|
<IfModule mod_expires.c>
|
|
ExpiresActive On
|
|
ExpiresByType text/html "access plus 1 hour"
|
|
ExpiresByType text/css "access plus 1 month"
|
|
ExpiresByType application/javascript "access plus 1 month"
|
|
ExpiresByType image/svg+xml "access plus 1 month"
|
|
ExpiresByType image/png "access plus 1 month"
|
|
ExpiresByType image/jpeg "access plus 1 month"
|
|
ExpiresByType image/webp "access plus 1 month"
|
|
ExpiresByType application/json "access plus 1 day"
|
|
</IfModule>
|