Add backend PIN verification and security hardening

- Add requirePin() check on add/update/delete endpoints (closes PIN bypass vulnerability)
- Restrict CORS to specific allowed origins only
- Add input length limits to sanitize() function
- Frontend now sends currentPin with all write requests
- Deploy script copies data/index.php to block directory listing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2025-12-23 22:30:39 -05:00
parent 08d550b0bd
commit 7e523392c0
3 changed files with 63 additions and 13 deletions

View File

@@ -790,6 +790,7 @@
let inventory = [];
let isUnlocked = false;
let currentPin = null;
let currentFilter = 'all';
let containerFilter = null;
let hasPinSet = false;
@@ -1080,6 +1081,7 @@
function toggleLock() {
if (isUnlocked) {
isUnlocked = false;
currentPin = null;
updateLockUI();
showToast('Locked');
} else {
@@ -1110,6 +1112,7 @@
if (result.success) {
isUnlocked = true;
currentPin = pin;
updateLockUI();
closeModal('pinModal');
document.getElementById('pinInput').value = '';
@@ -1149,6 +1152,7 @@
if (result.success) {
hasPinSet = true;
isUnlocked = true;
currentPin = newPin;
updateLockUI();
closeModal('setPinModal');
document.getElementById('newPinInput').value = '';
@@ -1231,9 +1235,10 @@
id: parseInt(editingId),
name,
container,
outOfStock
outOfStock,
pin: currentPin
});
const item = inventory.find(i => i.id === parseInt(editingId));
if (item) {
item.name = name;
@@ -1243,7 +1248,7 @@
showToast('Item updated');
} else {
// Add new
const result = await apiCall('add', { name, container, outOfStock });
const result = await apiCall('add', { name, container, outOfStock, pin: currentPin });
if (result.success && result.item) {
inventory.push(result.item);
@@ -1270,7 +1275,7 @@
showLoading();
try {
await apiCall('delete', { id: parseInt(editingId) });
await apiCall('delete', { id: parseInt(editingId), pin: currentPin });
inventory = inventory.filter(i => i.id !== parseInt(editingId));
renderInventory();