fix(tui,status,store): add delete confirm, input validation, XSS fix, history persistence
Prevent accidental deletes with y/n confirmation dialog. Validate all numeric form inputs (interval, port, timeout, threshold, retries) with range checks instead of silently defaulting to zero. Escape user-supplied data in status page JavaScript to close XSS via monitor names. Persist check history to new check_history table so sparklines and uptime percentages survive restarts.
This commit is contained in:
@@ -57,7 +57,15 @@ func (s *SQLiteStore) Init() error {
|
||||
username TEXT NOT NULL,
|
||||
public_key TEXT NOT NULL,
|
||||
role TEXT DEFAULT 'user'
|
||||
);`
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS check_history (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
site_id INTEGER NOT NULL,
|
||||
latency_ns INTEGER,
|
||||
is_up BOOLEAN,
|
||||
checked_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_check_history_site ON check_history(site_id, checked_at DESC);`
|
||||
_, err = s.db.Exec(createTables)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -204,7 +212,38 @@ func (s *SQLiteStore) DeleteUser(id int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// --- PHASE 5 ---
|
||||
func (s *SQLiteStore) SaveCheck(siteID int, latencyNs int64, isUp bool) {
|
||||
s.db.Exec("INSERT INTO check_history (site_id, latency_ns, is_up) VALUES (?, ?, ?)", siteID, latencyNs, isUp)
|
||||
s.db.Exec(`DELETE FROM check_history WHERE site_id = ? AND id NOT IN (
|
||||
SELECT id FROM check_history WHERE site_id = ? ORDER BY checked_at DESC LIMIT 1000
|
||||
)`, siteID, siteID)
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) LoadAllHistory(limit int) map[int][]models.CheckRecord {
|
||||
result := make(map[int][]models.CheckRecord)
|
||||
rows, err := s.db.Query(`
|
||||
SELECT site_id, latency_ns, is_up FROM (
|
||||
SELECT site_id, latency_ns, is_up,
|
||||
ROW_NUMBER() OVER (PARTITION BY site_id ORDER BY checked_at DESC) AS rn
|
||||
FROM check_history
|
||||
) WHERE rn <= ?`, limit)
|
||||
if err != nil {
|
||||
return result
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var r models.CheckRecord
|
||||
rows.Scan(&r.SiteID, &r.LatencyNs, &r.IsUp)
|
||||
result[r.SiteID] = append(result[r.SiteID], r)
|
||||
}
|
||||
for id, records := range result {
|
||||
for i, j := 0, len(records)-1; i < j; i, j = i+1, j-1 {
|
||||
records[i], records[j] = records[j], records[i]
|
||||
}
|
||||
result[id] = records
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *SQLiteStore) ExportData() models.Backup {
|
||||
return models.Backup{
|
||||
|
||||
Reference in New Issue
Block a user