check / check (push) Successful in 1m13s
The bot now serves an HTTP API on `PORT` (default 8080) beside the chat client, whose WebSocket stays on 127.0.0.1 inside the container. Every request needs `Authorization: Bearer` with the credential from the file named by `API_TOKEN_FILE`, compared in constant time; with no credential configured every request is refused, `OPTIONS *` included. `GET /api/v1/chats` lists the bot's chats. Responses carry the security headers from the repository policies; bodies, requests and the server are time- and size-bounded. The chat client stops only after the API has finished its requests. Disclosures: `contact_deleted` is an extra field; 404 and 405 answer in JSON; requests net/http cannot parse are refused by net/http without the security headers; three gosec findings are suppressed as false positives. Model: opus-5-5
47 lines
1.1 KiB
Go
47 lines
1.1 KiB
Go
package api
|
|
|
|
import (
|
|
"cmp"
|
|
"net/http"
|
|
"slices"
|
|
)
|
|
|
|
// handleChats lists the bot's chats, ordered by id. The bot talks to
|
|
// people only one to one, so its chats are its contacts, and a chat's
|
|
// id is its contact's.
|
|
func (h *handlers) handleChats() http.HandlerFunc {
|
|
type chat struct {
|
|
ID int64 `json:"id"`
|
|
DisplayName string `json:"display_name"`
|
|
ContactDeleted bool `json:"contact_deleted"`
|
|
}
|
|
|
|
type response struct {
|
|
Chats []chat `json:"chats"`
|
|
}
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
contacts, err := h.client.Contacts(r.Context(), h.userID)
|
|
if err != nil {
|
|
h.log.Error("listing the chats", "error", err)
|
|
h.respondError(w, http.StatusInternalServerError,
|
|
"the chats could not be read")
|
|
|
|
return
|
|
}
|
|
|
|
chats := make([]chat, 0, len(contacts))
|
|
for _, c := range contacts {
|
|
chats = append(chats, chat{
|
|
ID: c.ContactID,
|
|
DisplayName: c.Profile.DisplayName,
|
|
ContactDeleted: c.Deleted(),
|
|
})
|
|
}
|
|
|
|
slices.SortFunc(chats, func(a, b chat) int { return cmp.Compare(a.ID, b.ID) })
|
|
|
|
h.respond(w, http.StatusOK, response{Chats: chats})
|
|
}
|
|
}
|