// Copyright Jan Dittberner // SPDX-License-Identifier: GPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package matrix import ( "bytes" "crypto/rand" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "net/url" ) const transactionIDLength = 16 type Message struct { Type string `json:"msgtype"` Body string `json:"body"` FormattedBody string `json:"formatted_body"` Format string `json:"format"` } func SendMessage(server *url.URL, room string, token string, message string) error { messageBytes, err := json.Marshal(Message{ Type: TextMessage, Body: message, FormattedBody: message, Format: HTMLFormat, }) if err != nil { return fmt.Errorf("could not build JSON message: %w", err) } transaction, err := generateTransactionID() if err != nil { return err } postURL := server.JoinPath("/_matrix/client/r0/rooms/", room, "/send/m.room.message/", transaction) request, err := http.NewRequest(http.MethodPut, postURL.String(), bytes.NewBuffer(messageBytes)) if err != nil { return fmt.Errorf("could not build request: %w", err) } request.Header.Set("Accept", "application/json") request.Header.Set("Content-Type", "application/json") request.Header.Set("Authorization", "Bearer "+token) response, err := http.DefaultClient.Do(request) if err != nil { return fmt.Errorf("could not send request: %w", err) } defer func() { _ = response.Body.Close() }() if response.StatusCode > http.StatusBadRequest { responseBody, err := io.ReadAll(response.Body) if err != nil { return fmt.Errorf("received an error: %s, could not read response body: %w", response.Status, err) } return fmt.Errorf("received an error: %s %s", response.Status, string(responseBody)) } return nil } func generateTransactionID() (string, error) { IDBytes := make([]byte, transactionIDLength) _, err := rand.Read(IDBytes) if err != nil { return "", fmt.Errorf("could not generate transaction id: %w", err) } return base64.RawURLEncoding.EncodeToString(IDBytes), nil }