2020-09-28 20:37:02 +00:00
package event
2020-10-11 21:11:30 +00:00
import (
"bytes"
"encoding/json"
2020-10-17 10:07:39 +00:00
"errors"
2020-10-11 21:11:30 +00:00
"fmt"
"log"
2020-10-17 10:07:39 +00:00
"math/rand"
2020-10-11 21:11:30 +00:00
"net/http"
"strconv"
"time"
2020-10-12 14:16:28 +00:00
"git.nutfactory.org/hoernschen/Matrix/config"
"git.nutfactory.org/hoernschen/Matrix/entities/device"
"git.nutfactory.org/hoernschen/Matrix/entities/user"
"git.nutfactory.org/hoernschen/Matrix/utils"
2020-10-17 10:07:39 +00:00
2020-11-27 04:52:27 +00:00
"github.com/cenkalti/backoff/v4"
2020-10-11 21:11:30 +00:00
"github.com/gorilla/mux"
)
func New (
roomId string ,
sender string ,
origin string ,
timestamp int64 ,
eventType string ,
stateKey string ,
content string ,
txnId string ,
) ( err error , newEvent * Event ) {
err , eventId := utils . CreateUUID ( )
if err != nil {
return
}
id := generateEventId ( eventId )
newEvent = & Event {
Id : id ,
RoomId : roomId ,
Sender : sender ,
Origin : origin ,
Timestamp : timestamp ,
EventType : eventType ,
StateKey : stateKey ,
Content : content ,
Unsigned : UnsignedData {
TransactionId : txnId ,
} ,
}
newEvent . AuthEventHashes , err = GetAuthEvents ( newEvent )
if err != nil {
return
}
if eventType != "m.room.create" {
var depth int
newEvent . PrevEventHashes , depth , err = ReadEventsWithoutChild ( roomId )
if err != nil {
return
}
newEvent . Depth = depth + 1
}
newEvent . AuthEventHashes , err = GetAuthEvents ( newEvent )
if err != nil {
return
}
newEventBytesForHash , err := json . Marshal ( newEvent )
if err != nil {
return
}
err , newEvent . Hashes . SHA256 = utils . Hash ( newEventBytesForHash )
if err != nil {
return
}
newEvent . Unsigned = UnsignedData { }
newEventBytesForSign , err := json . Marshal ( newEvent )
if err != nil {
return
}
newEvent . Signatures = utils . SignContent ( newEventBytesForSign )
newEvent . Unsigned = UnsignedData {
TransactionId : txnId ,
}
return
}
func SendMessageHandler ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json; charset=UTF-8" )
2020-10-17 10:07:39 +00:00
request := SendMessageRequest { }
2020-10-11 21:11:30 +00:00
errResponse := utils . CheckRequest ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
token , errResponse := utils . GetAccessToken ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
foundUser , err := user . ReadUserFromAccessToken ( token )
if err != nil || foundUser == nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorCode : "M_UNKNOWN_TOKEN" , ErrorMessage : fmt . Sprintf ( "%s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
decoder := json . NewDecoder ( r . Body )
err = decoder . Decode ( & request )
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "Could not parse JSON: %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
vars := mux . Vars ( r )
roomId := vars [ "roomId" ]
eventType := vars [ "eventType" ]
txnId := vars [ "txnId" ]
if roomId == "" || eventType == "" || txnId == "" {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : "Missing Parameter" } ) ; err != nil {
panic ( err )
}
return
}
2020-10-17 10:07:39 +00:00
content , _ := json . Marshal ( request )
2020-10-11 21:11:30 +00:00
err , newEvent := New (
roomId ,
foundUser . Id ,
config . Homeserver ,
time . Now ( ) . Unix ( ) ,
eventType ,
foundUser . Id ,
2020-10-17 10:07:39 +00:00
string ( content ) ,
2020-10-11 21:11:30 +00:00
txnId ,
)
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "Error Creating Event: %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
err = CreateEvent ( newEvent , txnId )
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "Database Error: %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
transaction := & Transaction {
Id : txnId ,
Origin : config . Homeserver ,
Timestamp : time . Now ( ) . Unix ( ) ,
PDUS : [ ] * Event { newEvent } ,
}
servers , err := ReadServers ( roomId )
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "Database Error: %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
for _ , server := range servers {
2020-10-17 10:07:39 +00:00
if server != config . Homeserver {
log . Printf ( "Send Transaction to %s" , server )
2020-11-27 04:52:27 +00:00
operation := func ( ) error {
return SendTransaction ( transaction , server , config . HttpString , config . AuthentificationCheck )
}
notify := func ( err error , duration time . Duration ) {
log . Printf ( "Error Sending Transaction, retrying in %ss: %s" , duration / 1000000000 , err )
}
backoff . RetryNotify ( operation , backoff . NewExponentialBackOff ( ) , notify )
2020-10-11 21:11:30 +00:00
}
}
response := createEventResponse {
EventId : newEvent . Id ,
}
w . WriteHeader ( http . StatusOK )
if err := json . NewEncoder ( w ) . Encode ( response ) ; err != nil {
panic ( err )
}
}
func CreateStateEventHandler ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json; charset=UTF-8" )
errResponse := utils . CheckRequest ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
token , errResponse := utils . GetAccessToken ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
foundUser , err := user . ReadUserFromAccessToken ( token )
if err != nil || foundUser == nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorCode : "M_UNKNOWN_TOKEN" , ErrorMessage : fmt . Sprintf ( "%s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
vars := mux . Vars ( r )
roomId := vars [ "roomId" ]
eventType := vars [ "eventType" ]
stateKey := vars [ "stateKey" ]
if roomId == "" || eventType == "" {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : "Missing Parameter" } ) ; err != nil {
panic ( err )
}
return
}
buf := new ( bytes . Buffer )
buf . ReadFrom ( r . Body )
content := buf . String ( )
err , newEvent := New (
roomId ,
foundUser . Id ,
config . Homeserver ,
time . Now ( ) . Unix ( ) ,
eventType ,
stateKey ,
content ,
"" ,
)
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "Error Creating Event: %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
err = CreateEvent ( newEvent , "" )
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "Database Error: %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
err , txnId := utils . CreateUUID ( )
transaction := & Transaction {
Id : txnId ,
Origin : config . Homeserver ,
Timestamp : time . Now ( ) . Unix ( ) ,
PDUS : [ ] * Event { newEvent } ,
}
servers , err := ReadServers ( roomId )
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "Database Error: %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
for _ , server := range servers {
2020-11-27 04:52:27 +00:00
operation := func ( ) error {
2020-10-17 10:07:39 +00:00
return SendTransaction ( transaction , server , config . HttpString , config . AuthentificationCheck )
2020-10-11 21:11:30 +00:00
}
notify := func ( err error , duration time . Duration ) {
log . Printf ( "Error Sending Transaction, retrying in %ss: %s" , duration / 1000000000 , err )
}
2020-11-27 04:52:27 +00:00
go backoff . RetryNotify ( operation , backoff . NewExponentialBackOff ( ) , notify )
2020-10-11 21:11:30 +00:00
}
response := createEventResponse {
EventId : newEvent . Id ,
}
w . WriteHeader ( http . StatusOK )
if err := json . NewEncoder ( w ) . Encode ( response ) ; err != nil {
panic ( err )
}
}
func GetEventUserHandler ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json; charset=UTF-8" )
request := getEventRequest { }
errResponse := utils . CheckRequest ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
token , errResponse := utils . GetAccessToken ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
foundUser , err := user . ReadUserFromAccessToken ( token )
if err != nil || foundUser == nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorCode : "M_UNKNOWN_TOKEN" , ErrorMessage : fmt . Sprintf ( "%s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
decoder := json . NewDecoder ( r . Body )
err = decoder . Decode ( & request )
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "Could not parse JSON: %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
vars := mux . Vars ( r )
roomId := vars [ "roomId" ]
eventId := vars [ "eventId" ]
if roomId == "" || eventId == "" {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : "Missing Parameter" } ) ; err != nil {
panic ( err )
}
return
}
foundEvent , err := ReadEvent ( eventId )
if err != nil || foundEvent == nil {
w . WriteHeader ( http . StatusNotFound )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorCode : "M_NOT_FOUND" , ErrorMessage : fmt . Sprintf ( "Event not found. %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
response := getEventResponse {
Content : foundEvent . Content ,
EventType : foundEvent . EventType ,
}
w . WriteHeader ( http . StatusOK )
if err := json . NewEncoder ( w ) . Encode ( response ) ; err != nil {
panic ( err )
}
}
func GetStateEventHandler ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json; charset=UTF-8" )
errResponse := utils . CheckRequest ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
token , errResponse := utils . GetAccessToken ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
foundUser , err := user . ReadUserFromAccessToken ( token )
if err != nil || foundUser == nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorCode : "M_UNKNOWN_TOKEN" , ErrorMessage : fmt . Sprintf ( "%s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
vars := mux . Vars ( r )
roomId := vars [ "roomId" ]
eventType := vars [ "eventType" ]
stateKey := vars [ "stateKey" ]
if roomId == "" || eventType == "" {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : "Missing Parameter" } ) ; err != nil {
panic ( err )
}
return
}
foundEvent , err := ReadStateEvent ( roomId , eventType , stateKey )
if err != nil || foundEvent == nil {
w . WriteHeader ( http . StatusNotFound )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorCode : "M_NOT_FOUND" , ErrorMessage : fmt . Sprintf ( "Event not found. %s" , err ) } ) ; err != nil {
panic ( err )
}
return
}
w . WriteHeader ( http . StatusOK )
if err := json . NewEncoder ( w ) . Encode ( foundEvent . Content ) ; err != nil {
panic ( err )
}
}
func SyncEventsServerHandler ( w http . ResponseWriter , r * http . Request ) {
2020-10-17 10:07:39 +00:00
packetLossNumber := rand . Intn ( 100 )
if packetLossNumber > config . Packetloss {
w . Header ( ) . Set ( "Content-Type" , "application/json; charset=UTF-8" )
buf := new ( bytes . Buffer )
buf . ReadFrom ( r . Body )
request := syncEventsServerRequest { }
errResponse := utils . CheckRequest ( r )
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
2020-10-11 21:11:30 +00:00
}
2020-10-17 10:07:39 +00:00
_ = utils . CheckAuthHeader ( r , buf . String ( ) )
/ * if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
} * /
err := json . Unmarshal ( buf . Bytes ( ) , & request )
if err != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : fmt . Sprintf ( "SyncEventsServerHandler Could not parse JSON Request: %s" , err ) } ) ; err != nil {
panic ( err )
2020-10-11 21:11:30 +00:00
}
2020-10-17 10:07:39 +00:00
return
2020-10-11 21:11:30 +00:00
}
2020-10-17 10:07:39 +00:00
vars := mux . Vars ( r )
txnId := vars [ "txnId" ]
if txnId == "" {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : "SyncEventsServerHandler Missing Parameter" } ) ; err != nil {
panic ( err )
}
return
2020-10-11 21:11:30 +00:00
}
2020-10-17 10:07:39 +00:00
response := syncEventsServerResponse {
PDUs : make ( map [ string ] pduProcessingResult ) ,
2020-10-11 21:11:30 +00:00
}
2020-10-17 10:07:39 +00:00
missingEventIds := make ( map [ string ] [ ] string )
for _ , pdu := range request . PDUs {
signatureValid := CheckSignature ( * pdu )
if ! signatureValid {
log . Printf ( "Wrong Signature for Event %s" , pdu . Id )
response . PDUs [ pdu . Id ] = pduProcessingResult { ProcessingError : "Signature not valid" }
//continue
}
authEventsValid , err := CheckAuthEvents ( pdu )
if ! authEventsValid || err != nil {
log . Printf ( "Wrong Auth Events for Event %s" , pdu . Id )
response . PDUs [ pdu . Id ] = pduProcessingResult { ProcessingError : fmt . Sprintf ( "Error in Auth Check: %s" , err ) }
//continue
}
missingParentIds , err := CheckParents ( pdu )
if len ( missingParentIds ) > 0 || err != nil {
response . PDUs [ pdu . Id ] = pduProcessingResult { ProcessingError : fmt . Sprintf ( "Error in Parents Check: %s" , err ) }
for _ , parentId := range missingParentIds {
missingEventIds [ pdu . RoomId ] = append ( missingEventIds [ pdu . RoomId ] , parentId )
}
}
2020-10-11 21:11:30 +00:00
2020-10-17 10:07:39 +00:00
err = HandleEvent ( pdu , txnId )
if err != nil {
response . PDUs [ pdu . Id ] = pduProcessingResult { ProcessingError : fmt . Sprintf ( "Error in Event-Handling: %s" , err ) }
continue
}
2020-10-11 21:11:30 +00:00
2020-10-17 10:07:39 +00:00
response . PDUs [ pdu . Id ] = pduProcessingResult { }
}
2020-10-11 21:11:30 +00:00
2020-10-17 10:07:39 +00:00
if len ( missingEventIds ) > 0 {
for roomId , eventIds := range missingEventIds {
Backfill ( eventIds , roomId , request . Origin , config . HttpString , config . AuthentificationCheck )
2020-10-11 21:11:30 +00:00
}
}
2020-10-17 10:07:39 +00:00
w . WriteHeader ( http . StatusOK )
if err := json . NewEncoder ( w ) . Encode ( response ) ; err != nil {
panic ( err )
}
} else {
log . Println ( "Blocking Response" )
2020-10-11 21:11:30 +00:00
}
}
func BackfillHandler ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/json; charset=UTF-8" )
2020-10-17 10:07:39 +00:00
errResponse := utils . CheckAuthHeader ( r , "" )
2020-10-11 21:11:30 +00:00
if errResponse != nil {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( errResponse ) ; err != nil {
panic ( err )
}
return
}
vars := mux . Vars ( r )
roomId := vars [ "roomId" ]
if roomId == "" {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : "Missing Parameter" } ) ; err != nil {
panic ( err )
}
return
}
limit := 50
eventIds , ok := r . URL . Query ( ) [ "v" ]
if ! ok || eventIds [ 0 ] == "" {
w . WriteHeader ( http . StatusBadRequest )
if err := json . NewEncoder ( w ) . Encode ( utils . ErrorResponse { ErrorMessage : "Missing Parameter" } ) ; err != nil {
panic ( err )
}
return
}
limitString := r . URL . Query ( ) . Get ( "limit" )
if limitString != "" {
limit , _ = strconv . Atoi ( limitString )
}
pdus := [ ] * Event { }
for len ( pdus ) < limit {
newEventIds := [ ] string { }
for _ , eventId := range eventIds {
foundEvent , err := ReadEvent ( eventId )
if err != nil || foundEvent == nil {
2020-10-17 10:07:39 +00:00
continue
2020-10-11 21:11:30 +00:00
}
for newEventId , _ := range foundEvent . PrevEventHashes {
newEventIds = append ( newEventIds , newEventId )
}
pdus = append ( pdus , foundEvent )
}
eventIds = newEventIds
}
response := backfillResponse {
Origin : config . Homeserver ,
Timestamp : time . Now ( ) . Unix ( ) ,
PDUs : pdus ,
}
w . WriteHeader ( http . StatusOK )
if err := json . NewEncoder ( w ) . Encode ( response ) ; err != nil {
panic ( err )
}
}
2020-10-17 10:07:39 +00:00
func SendTransaction ( transaction * Transaction , homeserver string , httpString string , authentification bool ) ( err error ) {
requestUrl := fmt . Sprintf ( "%s://%s/_matrix/federation/v1/send/%s?" , httpString , homeserver , transaction . Id )
2020-10-11 21:11:30 +00:00
request := syncEventsServerRequest {
Origin : transaction . Origin ,
Timestamp : transaction . Timestamp ,
PDUs : transaction . PDUS ,
}
reqBody , err := json . Marshal ( request )
if err != nil {
return
}
2020-10-17 10:07:39 +00:00
client := & http . Client { Timeout : 2 * time . Second }
2020-10-11 21:11:30 +00:00
req , err := http . NewRequest ( http . MethodPut , requestUrl , bytes . NewBuffer ( reqBody ) )
if err != nil {
return
}
2020-10-17 10:07:39 +00:00
if authentification {
var authHeader string
authHeader , err = utils . CreateAuthHeader ( http . MethodPut , requestUrl , homeserver , string ( reqBody ) )
if err != nil {
return
}
req . Header [ "Authorization" ] = [ ] string { authHeader }
}
req . Header [ "Content-Type" ] = [ ] string { "application/json" }
r , err := client . Do ( req )
if err != nil {
return
}
if r . StatusCode != http . StatusOK {
utils . HandleHTTPError ( r )
} else {
buf := new ( bytes . Buffer )
buf . ReadFrom ( r . Body )
content := buf . String ( )
if content == "" {
err = errors . New ( "Missing Response" )
return
}
}
2020-10-11 21:11:30 +00:00
return
}
2020-10-17 10:07:39 +00:00
func Backfill ( eventIds [ ] string , roomId string , homeserver string , httpString string , authentification bool ) ( err error ) {
requestUrl := fmt . Sprintf ( "%s://%s/_matrix/federation/v1/backfill/%s?" , httpString , homeserver , roomId )
2020-10-11 21:11:30 +00:00
for _ , eventId := range eventIds {
requestUrl = fmt . Sprintf ( "%sv=%s&" , requestUrl , eventId )
}
2020-10-17 10:07:39 +00:00
client := & http . Client { Timeout : 2 * time . Second }
var req * http . Request
req , err = http . NewRequest ( http . MethodGet , requestUrl , bytes . NewBuffer ( nil ) )
2020-10-11 21:11:30 +00:00
if err != nil {
return
}
2020-10-17 10:07:39 +00:00
if authentification {
var authHeader string
authHeader , err = utils . CreateAuthHeader ( http . MethodGet , requestUrl , homeserver , "" )
if err != nil {
return
}
req . Header [ "Authorization" ] = [ ] string { authHeader }
}
req . Header [ "Content-Type" ] = [ ] string { "application/json" }
r , err := client . Do ( req )
if err != nil {
return
}
if r . StatusCode != http . StatusOK {
errResponse := utils . HandleHTTPError ( r )
log . Fatalf ( "%s (%s)" , errResponse . ErrorMessage , errResponse . ErrorCode )
}
2020-10-11 21:11:30 +00:00
response := backfillResponse { }
defer r . Body . Close ( )
decoder := json . NewDecoder ( r . Body )
err = decoder . Decode ( & response )
if err != nil {
return
}
var missingEventIds [ ] string
for _ , pdu := range response . PDUs {
for i , eventId := range missingEventIds {
if pdu . Id == eventId {
missingEventIds = append ( missingEventIds [ : i ] , missingEventIds [ i + 1 : ] ... )
}
}
signatureValid := CheckSignature ( * pdu )
if ! signatureValid {
log . Printf ( "Wrong Signature for Event %s" , pdu . Id )
missingEventIds = append ( missingEventIds , pdu . Id )
continue
}
authEventsValid , err := CheckAuthEvents ( pdu )
if ! authEventsValid || err != nil {
log . Printf ( "Wrong Auth Events for Event %s" , pdu . Id )
missingEventIds = append ( missingEventIds , pdu . Id )
}
missingParentIds , err := CheckParents ( pdu )
if len ( missingParentIds ) > 0 || err != nil {
for _ , parentId := range missingParentIds {
missingEventIds = append ( missingEventIds , parentId )
}
}
2020-10-17 10:07:39 +00:00
err = HandleEvent ( pdu , "" )
2020-10-11 21:11:30 +00:00
if err != nil {
log . Printf ( "Error in Event-Handling: %s" , err )
continue
}
}
if len ( missingEventIds ) > 0 {
2020-10-17 10:07:39 +00:00
Backfill ( missingEventIds , roomId , homeserver , config . HttpString , config . AuthentificationCheck )
2020-10-11 21:11:30 +00:00
}
return
}
func generateEventId ( id string ) string {
return fmt . Sprintf ( "$%s:%s" , id , config . Homeserver )
}
func GetAuthChain ( newEvent * Event ) ( authChain [ ] * Event , err error ) {
2020-10-17 10:07:39 +00:00
if ! config . AuthentificationCheck {
return
}
2020-10-11 21:11:30 +00:00
createEvent , err := ReadStateEvent ( newEvent . RoomId , "m.room.create" , "" )
if err != nil {
return
}
if createEvent != nil {
authChain = append ( authChain , createEvent )
}
powerLevelEvent , err := ReadStateEvent ( newEvent . RoomId , "m.room.power_levels" , "" )
if err != nil {
return
}
if powerLevelEvent != nil {
authChain = append ( authChain , powerLevelEvent )
}
stateKey := newEvent . Sender
if newEvent . EventType == "m.room.member" {
stateKey = newEvent . StateKey
}
memberEvent , err := ReadStateEvent ( newEvent . RoomId , "m.room.member" , stateKey )
if err != nil {
return
}
if memberEvent != nil {
authChain = append ( authChain , memberEvent )
}
joinRuleEvent , err := ReadStateEvent ( newEvent . RoomId , "m.room.join_rules" , "" )
if err != nil {
return
}
if joinRuleEvent != nil && newEvent . EventType == "m.room.member" {
authChain = append ( authChain , joinRuleEvent )
}
return
}
func GetAuthEvents ( newEvent * Event ) ( authEventHashes map [ string ] EventHash , err error ) {
authEventHashes = make ( map [ string ] EventHash )
authChain , err := GetAuthChain ( newEvent )
if err != nil {
return
}
for _ , authEvent := range authChain {
authEventHashes [ authEvent . Id ] = authEvent . Hashes
}
return
}
func CheckEventHash ( id string , hash EventHash ) ( correct bool , eventFound bool , err error ) {
foundEvent , err := ReadEvent ( id )
correct = true
eventFound = true
if err != nil {
return
}
if foundEvent == nil {
eventFound = false
return
}
if hash . SHA256 != foundEvent . Hashes . SHA256 {
correct = false
return
}
return
}
func CheckParents ( eventToCheck * Event ) ( missingParentIds [ ] string , err error ) {
2020-10-17 10:07:39 +00:00
if config . Consensus {
for key , hash := range eventToCheck . PrevEventHashes {
correctHash , foundEvent , err := CheckEventHash ( key , hash )
if ! correctHash || ! foundEvent || err != nil {
missingParentIds = append ( missingParentIds , key )
}
2020-10-11 21:11:30 +00:00
}
}
return
}
func CheckAuthEvents ( eventToCheck * Event ) ( correct bool , err error ) {
correct = true
2020-10-17 10:07:39 +00:00
if ! config . AuthentificationCheck {
return
}
2020-10-11 21:11:30 +00:00
authEvents , err := GetAuthEvents ( eventToCheck )
if err != nil {
return
}
for key , hash := range authEvents {
if eventToCheck . AuthEventHashes [ key ] . SHA256 != hash . SHA256 {
2020-10-17 10:07:39 +00:00
//correct = false
2020-10-11 21:11:30 +00:00
return
}
}
return
}
func CheckSignature ( eventToCheck Event ) ( correct bool ) {
2020-10-17 10:07:39 +00:00
if ! config . Signing {
correct = true
return
}
2020-10-11 21:11:30 +00:00
correct = false
signatures := eventToCheck . Signatures
eventToCheck . Unsigned = UnsignedData { }
eventToCheck . Signatures = nil
jsonString , err := json . Marshal ( eventToCheck )
if err != nil {
return
}
2020-10-17 10:07:39 +00:00
for id , signature := range signatures [ eventToCheck . Origin ] {
verifyKey , err := device . GetVerifyKey ( eventToCheck . Origin , id )
if err == nil && verifyKey != nil {
correct = utils . VerifySignature ( verifyKey , jsonString , signature )
2020-10-11 21:11:30 +00:00
}
}
return
}
2020-10-17 10:07:39 +00:00
func HandleEvents ( events [ ] * Event , txnId string ) ( err error ) {
2020-10-11 21:11:30 +00:00
for _ , eventToHandle := range events {
2020-10-17 10:07:39 +00:00
err = HandleEvent ( eventToHandle , txnId )
2020-10-11 21:11:30 +00:00
}
return
}
2020-10-17 10:07:39 +00:00
func HandleEvent ( eventToHandle * Event , txnId string ) ( err error ) {
log . Printf ( "EventType: %s" , eventToHandle . EventType )
foundEvent , err := ReadEvent ( eventToHandle . Id )
if foundEvent == nil && err == nil {
err = CreateEvent ( eventToHandle , txnId )
}
if err != nil {
return
}
2020-10-11 21:11:30 +00:00
if eventToHandle . EventType == "m.room.message" {
2020-10-17 10:07:39 +00:00
log . Printf ( "%s: %s" , eventToHandle . Sender , eventToHandle . Content )
2020-10-11 21:11:30 +00:00
} else if eventToHandle . EventType == "m.room.member" {
message := MemberEventContent { }
err = json . Unmarshal ( [ ] byte ( eventToHandle . Content ) , & message )
if err != nil {
return
}
if message . Membership == "join" {
2020-10-17 10:07:39 +00:00
log . Printf ( "Join %s to Room %s" , eventToHandle . StateKey , eventToHandle . RoomId )
}
err = CreateRoomMember ( eventToHandle . RoomId , eventToHandle . StateKey , eventToHandle . Origin )
if err != nil {
return
2020-10-11 21:11:30 +00:00
}
}
2020-10-01 15:45:57 +00:00
return
}