Hardening pass over the API surface. No route's auth requirements change.
Resilience:
- Add recover middleware. There was none, so an unhandled panic in any
handler propagated out of the process instead of becoming a 500.
- Add a centralized ErrorHandler so errors and recovered panics return the
same {success,message} envelope as the utils helpers, not Fiber's default
plain-text body. 5xx responses are logged with method and path.
Rate limiting:
- Global 300/min per IP as an abuse backstop, exempting health/readiness
probes and websocket upgrades.
- 10/min shared across every credential endpoint (customer/miler/admin/hub
login, verify-pin, reset-pin, email OTP). PINs are 4 digits, so the whole
keyspace was previously walkable in seconds. One shared limiter instance
means rotating between endpoints doesn't reset the budget.
- Add TRUSTED_PROXIES config. Limits key on c.IP(), which behind a TLS
terminator is the proxy, collapsing every client into one bucket. When set,
X-Forwarded-For is honoured only from those proxies so the header can't be
spoofed to dodge the limit. Logs a warning when unset.
Transactions:
- Check the error on all 51 previously-unchecked tx.Save/Create/Delete/
Model(...).Update/Commit calls across 6 controllers. A failed write inside
a transaction was silently ignored and the request still reported success;
an unchecked Commit could fail with the caller told everything worked.
Each site now rolls back and returns a specific message.
Pagination:
- Add utils.ParsePage/Paginated, reusing the pageno/pagesize convention
GetAdminBookings already established. Default 500, hard cap 1000.
- Apply to the previously unbounded consignments, tripsheets, exceptions,
app-users and clients endpoints. Defaults are high so existing consoles
that don't paginate keep working; the cap only stops a growing table from
being loaded wholesale. total is now a real COUNT, not len(data).
- GetClients also loaded the entire auth table to join in memory; it now
fetches only the current page's rows.
Tests (first in the repo):
- Extract the hyperlocal pincode rule out of BookingPickupComplete into
isHyperlocal so it is testable, covering the short/empty pincode fallback.
- Cover calculateVolumetricWeight and the ParsePage clamping rules.
Repo hygiene:
- Tag scratch/*.go with //go:build ignore. Each declared its own main(), so
`go build ./...` failed on redeclaration; it now passes repo-wide.
- Untrack scratch/node_modules (216 files) and ignore node_modules, test
artifacts, and the `doormile` binary `go build .` emits.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
60 lines
1.4 KiB
Go
60 lines
1.4 KiB
Go
//go:build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"log"
|
|
|
|
_ "github.com/lib/pq"
|
|
)
|
|
|
|
func main() {
|
|
dsn := "host=31.97.228.132 user=admin password=Package@321# dbname=logistics port=5433 sslmode=disable"
|
|
db, err := sql.Open("postgres", dsn)
|
|
if err != nil {
|
|
log.Fatalf("Open failed: %v", err)
|
|
}
|
|
defer db.Close()
|
|
|
|
if err := db.Ping(); err != nil {
|
|
log.Fatalf("Ping failed: %v", err)
|
|
}
|
|
fmt.Println("Connected OK")
|
|
|
|
// Drop the old constraint
|
|
_, err = db.Exec(`ALTER TABLE pickupbookings DROP CONSTRAINT IF EXISTS pickupbookings_status_check`)
|
|
if err != nil {
|
|
log.Fatalf("Drop constraint failed: %v", err)
|
|
}
|
|
fmt.Println("Old constraint dropped.")
|
|
|
|
// Recreate with all status values from constants
|
|
_, err = db.Exec(`
|
|
ALTER TABLE pickupbookings ADD CONSTRAINT pickupbookings_status_check
|
|
CHECK (status IN (
|
|
'Pending_Pickup',
|
|
'Created',
|
|
'Miler_Assigned',
|
|
'Pickup_Scheduled',
|
|
'Picked_Up',
|
|
'Converted_To_Consignment',
|
|
'Cancelled'
|
|
))
|
|
`)
|
|
if err != nil {
|
|
log.Fatalf("Add constraint failed: %v", err)
|
|
}
|
|
fmt.Println("New constraint added with Pending_Pickup included.")
|
|
|
|
// Verify
|
|
var def string
|
|
db.QueryRow(`
|
|
SELECT pg_get_constraintdef(con.oid)
|
|
FROM pg_constraint con
|
|
JOIN pg_class rel ON rel.oid = con.conrelid
|
|
WHERE rel.relname = 'pickupbookings' AND con.contype = 'c'
|
|
`).Scan(&def)
|
|
fmt.Println("Current constraint:", def)
|
|
} |