HTTP API: server, credential and the list of chats (closes #4)
check / check (push) Successful in 1m13s
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
This commit was merged in pull request #12.
This commit is contained in:
@@ -14,6 +14,7 @@ const (
|
||||
TypeUserContactLink = "userContactLink"
|
||||
TypeUserContactLinkCreated = "userContactLinkCreated"
|
||||
TypeUserContactLinkUpdated = "userContactLinkUpdated"
|
||||
TypeContactsList = "contactsList"
|
||||
TypeNewChatItems = "newChatItems"
|
||||
TypeContactConnected = "contactConnected"
|
||||
TypeChatCmdError = "chatCmdError"
|
||||
@@ -46,10 +47,14 @@ func (e Event) Decode(v any) error {
|
||||
type (
|
||||
// User is the chat client's local user profile: the bot itself.
|
||||
User struct {
|
||||
UserID int64 `json:"userId"`
|
||||
Profile struct {
|
||||
DisplayName string `json:"displayName"`
|
||||
} `json:"profile"`
|
||||
UserID int64 `json:"userId"`
|
||||
Profile Profile `json:"profile"`
|
||||
}
|
||||
|
||||
// Profile is how the bot or a contact presents itself. Nothing
|
||||
// makes a display name unique.
|
||||
Profile struct {
|
||||
DisplayName string `json:"displayName"`
|
||||
}
|
||||
|
||||
// ConnLink is a SimpleX link. The short form is what people share;
|
||||
@@ -61,7 +66,9 @@ type (
|
||||
|
||||
// Contact is a person connected to the bot.
|
||||
Contact struct {
|
||||
ContactID int64 `json:"contactId"`
|
||||
ContactID int64 `json:"contactId"`
|
||||
Profile Profile `json:"profile"`
|
||||
Status string `json:"contactStatus"`
|
||||
}
|
||||
|
||||
// NewChatItems is the record of a newChatItems event: messages
|
||||
@@ -142,6 +149,13 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
// Deleted reports whether the contact is gone, as it is once the person
|
||||
// deletes their chat with the bot. The chat client still lists such a
|
||||
// contact, with its chat, but nothing more reaches them.
|
||||
func (c Contact) Deleted() bool {
|
||||
return c.Status != "active"
|
||||
}
|
||||
|
||||
// Message is a text message a contact sent to the bot.
|
||||
type Message struct {
|
||||
ContactID int64
|
||||
@@ -190,6 +204,10 @@ func cmdSetAddressSettings(userID int64, s AddressSettings) (string, error) {
|
||||
return "/_address_settings " + strconv.FormatInt(userID, 10) + " " + string(b), nil
|
||||
}
|
||||
|
||||
func cmdListContacts(userID int64) string {
|
||||
return "/_contacts " + strconv.FormatInt(userID, 10)
|
||||
}
|
||||
|
||||
func cmdSendText(contactID, quotedItemID int64, text string) (string, error) {
|
||||
b, err := json.Marshal([]composedMessage{{
|
||||
QuotedItemID: quotedItemID,
|
||||
|
||||
Reference in New Issue
Block a user