fix: harden API, DB, and web layer from audit findings

- Cap list API limit at 200 to prevent unbounded queries
- Sanitize markdown output with DOMPurify to prevent XSS
- Add v4 migration with indexes on deleted_at and modified_at
- Fix v2 migration swallowed ALTER TABLE errors
- Tighten ~/.nib directory permissions to 0o700
This commit is contained in:
2026-05-20 20:41:53 -04:00
parent 1ac4196547
commit 8663beeb96
5 changed files with 54 additions and 5 deletions
+21 -4
View File
@@ -51,7 +51,7 @@ func (s *Store) Close() error {
return s.db.Close()
}
const currentSchema = 3
const currentSchema = 4
var migrations = []func(db *sql.DB) error{
// v1: initial schema
@@ -92,8 +92,12 @@ var migrations = []func(db *sql.DB) error{
// v2: add title and description columns
func(db *sql.DB) error {
db.Exec(`ALTER TABLE entities ADD COLUMN title TEXT`)
db.Exec(`ALTER TABLE entities ADD COLUMN description TEXT`)
if _, err := db.Exec(`ALTER TABLE entities ADD COLUMN title TEXT`); err != nil {
return fmt.Errorf("add title column: %w", err)
}
if _, err := db.Exec(`ALTER TABLE entities ADD COLUMN description TEXT`); err != nil {
return fmt.Errorf("add description column: %w", err)
}
return nil
},
@@ -166,6 +170,19 @@ var migrations = []func(db *sql.DB) error{
return tx.Commit()
},
// v4: add indexes for common query filters
func(db *sql.DB) error {
for _, idx := range []string{
`CREATE INDEX IF NOT EXISTS idx_entities_deleted ON entities(deleted_at)`,
`CREATE INDEX IF NOT EXISTS idx_entities_modified ON entities(modified_at DESC) WHERE deleted_at IS NULL`,
} {
if _, err := db.Exec(idx); err != nil {
return fmt.Errorf("create index: %w", err)
}
}
return nil
},
}
func (s *Store) migrate() error {
@@ -200,7 +217,7 @@ func DefaultPath() (string, error) {
return "", err
}
dir := filepath.Join(home, ".nib")
if err := os.MkdirAll(dir, 0o755); err != nil {
if err := os.MkdirAll(dir, 0o700); err != nil {
return "", err
}
return filepath.Join(dir, "nib.db"), nil