mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-07 07:59:42 +02:00
fix: code cleanup — path traversal, test leaks, dead code, consistency
- Add path traversal protection to GET /api/cases/:name and fix-plan - Use safePathSchema for LinkCaseSchema.path - Fix QR auth test timer leak (afterAll → afterEach) and env var try/finally - Remove dead terminal size check after Zod validation in resize route - Remove no-op sampleCount guard in adaptive timing - Replace hardcoded values with constants in notification-manager and subagent-windows - Add Zod validation to POST /api/auth/revoke - Use _apiPut instead of raw fetch in subagent-windows - Add SwipeHandler.cleanup() for consistency with other mobile handlers - Move NiceConfig/ProcessStats from types/plan.ts to types/common.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -403,6 +403,10 @@ const SwipeHandler = {
|
||||
maxSwipeTime: 300, // Maximum ms for a swipe gesture
|
||||
maxVerticalDrift: 100, // Max vertical movement allowed
|
||||
|
||||
_touchStartHandler: null,
|
||||
_touchEndHandler: null,
|
||||
_element: null,
|
||||
|
||||
/** Initialize swipe handling */
|
||||
init() {
|
||||
// Only on touch devices
|
||||
@@ -411,8 +415,22 @@ const SwipeHandler = {
|
||||
const terminal = document.querySelector('.main');
|
||||
if (!terminal) return;
|
||||
|
||||
terminal.addEventListener('touchstart', (e) => this.onTouchStart(e), { passive: true });
|
||||
terminal.addEventListener('touchend', (e) => this.onTouchEnd(e), { passive: true });
|
||||
this._element = terminal;
|
||||
this._touchStartHandler = (e) => this.onTouchStart(e);
|
||||
this._touchEndHandler = (e) => this.onTouchEnd(e);
|
||||
terminal.addEventListener('touchstart', this._touchStartHandler, { passive: true });
|
||||
terminal.addEventListener('touchend', this._touchEndHandler, { passive: true });
|
||||
},
|
||||
|
||||
/** Remove swipe listeners */
|
||||
cleanup() {
|
||||
if (this._element && this._touchStartHandler) {
|
||||
this._element.removeEventListener('touchstart', this._touchStartHandler);
|
||||
this._element.removeEventListener('touchend', this._touchEndHandler);
|
||||
}
|
||||
this._touchStartHandler = null;
|
||||
this._touchEndHandler = null;
|
||||
this._element = null;
|
||||
},
|
||||
|
||||
onTouchStart(e) {
|
||||
|
||||
@@ -188,9 +188,9 @@ class NotificationManager {
|
||||
count: 1,
|
||||
};
|
||||
|
||||
// Add to log (cap at 100)
|
||||
// Add to log (cap at NOTIFICATION_LIST_CAP)
|
||||
this.notifications.unshift(notification);
|
||||
if (this.notifications.length > 100) this.notifications.pop();
|
||||
if (this.notifications.length > NOTIFICATION_LIST_CAP) this.notifications.pop();
|
||||
|
||||
// Track for grouping
|
||||
const timeout = setTimeout(() => this.groupingMap.delete(groupKey), GROUPING_TIMEOUT_MS);
|
||||
@@ -298,9 +298,9 @@ class NotificationManager {
|
||||
}
|
||||
if (Notification.permission !== 'granted') return;
|
||||
|
||||
// Rate limit: max 1 per 3 seconds
|
||||
// Rate limit
|
||||
const now = Date.now();
|
||||
if (now - this.lastBrowserNotifTime < 3000) return;
|
||||
if (now - this.lastBrowserNotifTime < BROWSER_NOTIF_RATE_LIMIT_MS) return;
|
||||
this.lastBrowserNotifTime = now;
|
||||
|
||||
const notif = new Notification(`Codeman: ${title}`, {
|
||||
@@ -318,8 +318,8 @@ class NotificationManager {
|
||||
notif.close();
|
||||
};
|
||||
|
||||
// Auto-close after 8s
|
||||
setTimeout(() => notif.close(), 8000);
|
||||
// Auto-close
|
||||
setTimeout(() => notif.close(), AUTO_CLOSE_NOTIFICATION_MS);
|
||||
}
|
||||
|
||||
async requestPermission() {
|
||||
|
||||
@@ -111,11 +111,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
|
||||
// Save to server for cross-browser persistence
|
||||
try {
|
||||
await fetch('/api/subagent-window-states', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(windowStates)
|
||||
});
|
||||
await this._apiPut('/api/subagent-window-states', windowStates);
|
||||
} catch (err) {
|
||||
console.error('Failed to save subagent window states to server:', err);
|
||||
}
|
||||
@@ -178,7 +174,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
if (windowData && windowData.element) {
|
||||
// Parse position values and clamp to viewport
|
||||
let left = parseInt(position.left, 10) || 50;
|
||||
let top = parseInt(position.top, 10) || 120;
|
||||
let top = parseInt(position.top, 10) || WINDOW_INITIAL_TOP_PX;
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
const windowWidth = 420;
|
||||
@@ -545,7 +541,7 @@ Object.assign(CodemanApp.prototype, {
|
||||
} else {
|
||||
// Normal positioning
|
||||
startX = 50;
|
||||
startY = 120;
|
||||
startY = WINDOW_INITIAL_TOP_PX;
|
||||
maxCols = Math.floor((viewportWidth - startX - 50) / (windowWidth + gap)) || 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user