diff --git a/.vscode/launch.json b/.vscode/launch.json index c20cb3f..e756412 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "go", "request": "launch", "mode": "auto", - "program": "${workspaceFolder}/main.go", + "program": "${workspaceFolder}/workloadGenerator.go", "env": {}, "args": [] } diff --git a/1602853607 Baseline Measurement Windows.csv b/1602853607 Baseline Measurement Windows.csv new file mode 100644 index 0000000..bb48dda --- /dev/null +++ b/1602853607 Baseline Measurement Windows.csv @@ -0,0 +1,11 @@ +Iteration,Start,End +1,1602853607,1602853727 +2,1602853727,1602853847 +3,1602853847,1602853967 +4,1602853967,1602854087 +5,1602854087,1602854207 +6,1602854207,1602854327 +7,1602854327,1602854447 +8,1602854447,1602854567 +9,1602854567,1602854687 +10,1602854687,1602854807 diff --git a/config/config.go b/config/config.go index 6f747c1..abe58da 100644 --- a/config/config.go +++ b/config/config.go @@ -1,5 +1,11 @@ package config +import ( + "time" + + "github.com/lestrrat-go/backoff" +) + var ServerName string = "Hoernschen's Matrix Server" var Version string = "0.1" @@ -11,11 +17,22 @@ var PublicKey []byte var KeyId string var VerifyKeys map[string]map[string][]byte -// Parameters for Mesurements -// TODO: Implement correctly -var Packetloss float32 -var UnavailableTill int +var Packetloss int +var UnavailableTill int64 +var Consensus bool var AuthentificationCheck bool var Signing bool var Encryption bool var HttpString string + +var BackoffPolicy *backoff.Exponential + +func SetDefaultParams() { + Packetloss = 0.0 + UnavailableTill = time.Now().Unix() + Consensus = true + AuthentificationCheck = true + Signing = true + Encryption = true + HttpString = "https" +} diff --git a/entities/device/deviceDatabaseConnector.go b/entities/device/deviceDatabaseConnector.go index 3c0337b..b82cd67 100644 --- a/entities/device/deviceDatabaseConnector.go +++ b/entities/device/deviceDatabaseConnector.go @@ -2,7 +2,6 @@ package device import ( "fmt" - "log" "git.nutfactory.org/hoernschen/Matrix/utils/database" ) @@ -26,6 +25,7 @@ func CreateDevice(device *Device, userId string) (err error) { _, err = stmt.Exec(device.Id, device.Name, device.AccessToken, userId) if err != nil { + tx.Rollback() return } tx.Commit() @@ -60,7 +60,7 @@ func ReadDeviceFromAccessToken(accessToken string) (foundDevice *Device, err err queryStmt := fmt.Sprintf(`SELECT id, name, accessToken FROM device WHERE accessToken = '%s'`, accessToken) - log.Printf(queryStmt) + rows, err := database.DB.Query(queryStmt) if err != nil { return @@ -126,6 +126,7 @@ func UpdateDevice(device *Device) (err error) { _, err = stmt.Exec(device.Name, device.AccessToken, device.Id) if err != nil { + tx.Rollback() return } @@ -142,8 +143,9 @@ func DeleteDevice(id string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } diff --git a/entities/device/key.go b/entities/device/key.go index b737f03..41c0d4d 100644 --- a/entities/device/key.go +++ b/entities/device/key.go @@ -6,7 +6,7 @@ type Key struct { Key []byte `json:"key,omitempty"` } -type serverKeys struct { +type ServerKeys struct { ServerName string `json:"server_name,omitempty"` VerifyKeys map[string]verifyKey `json:"verify_keys,omitempty"` OldVerifyKeys map[string]verifyKey `json:"old_verify_keys,omitempty"` diff --git a/entities/device/keyController.go b/entities/device/keyController.go index 961a799..9f71b02 100644 --- a/entities/device/keyController.go +++ b/entities/device/keyController.go @@ -1,9 +1,12 @@ package device import ( + "bytes" + "encoding/base64" "encoding/json" "fmt" "net/http" + "time" "git.nutfactory.org/hoernschen/Matrix/config" "git.nutfactory.org/hoernschen/Matrix/utils" @@ -28,11 +31,11 @@ func GetServerSigningKeyHandler(w http.ResponseWriter, r *http.Request) { } return } - response := serverKeys{ + response := ServerKeys{ ServerName: config.Homeserver, VerifyKeys: make(map[string]verifyKey), } - response.VerifyKeys[config.KeyId] = verifyKey{Key: string(config.PublicKey)} + response.VerifyKeys[config.KeyId] = verifyKey{Key: base64.RawStdEncoding.EncodeToString(config.PublicKey)} content, err := json.Marshal(response) if err != nil { w.WriteHeader(http.StatusBadRequest) @@ -50,26 +53,36 @@ func GetServerSigningKeyHandler(w http.ResponseWriter, r *http.Request) { } } -// TODO: Use Function -func getVerifyKey(server string, id string) (key []byte, err error) { +func GetVerifyKey(server string, id string) (key []byte, err error) { if val, ok := config.VerifyKeys[server][id]; ok { key = val } else { - httpString := "https" - requestUrl := fmt.Sprintf("%s://%s/_matrix/key/v2/server", httpString, server) - var res *http.Response - res, err = http.Get(requestUrl) + requestUrl := fmt.Sprintf("%s://%s/_matrix/key/v2/server", config.HttpString, server) + client := &http.Client{Timeout: 2 * time.Second} + var req *http.Request + req, err = http.NewRequest(http.MethodGet, requestUrl, bytes.NewBuffer(nil)) if err != nil { return } - serverKeyRes := serverKeys{} + var res *http.Response + res, err = client.Do(req) + if err != nil { + return + } + if res.StatusCode != http.StatusOK { + utils.HandleHTTPError(res) + } + serverKeyRes := ServerKeys{} decoder := json.NewDecoder(res.Body) err = decoder.Decode(&serverKeyRes) config.VerifyKeys[server] = make(map[string][]byte) for keyId, verifyKey := range serverKeyRes.VerifyKeys { - config.VerifyKeys[server][keyId] = []byte(verifyKey.Key) - if id == keyId { - key = []byte(verifyKey.Key) + verifyKeyBytes, err := base64.RawStdEncoding.DecodeString(verifyKey.Key) + if err == nil { + config.VerifyKeys[server][keyId] = verifyKeyBytes + if id == keyId { + key = verifyKeyBytes + } } } } diff --git a/entities/device/keyDatabaseConnector.go b/entities/device/keyDatabaseConnector.go index cfae693..2355801 100644 --- a/entities/device/keyDatabaseConnector.go +++ b/entities/device/keyDatabaseConnector.go @@ -25,6 +25,7 @@ func CreateKey(key *Key, deviceId string) (err error) { _, err = stmt.Exec(key.Id, key.Type, key.Key, deviceId) if err != nil { + tx.Rollback() return } tx.Commit() @@ -99,6 +100,7 @@ func UpdateKey(key *Key) (err error) { _, err = stmt.Exec(key.Type, key.Key, key.Id) if err != nil { + tx.Rollback() return } @@ -115,8 +117,9 @@ func DeleteKey(id string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } diff --git a/entities/event/event.go b/entities/event/event.go index 8d72227..e0abcdc 100644 --- a/entities/event/event.go +++ b/entities/event/event.go @@ -86,7 +86,7 @@ type Notifications struct { Room int `json:"room,omitempty"` } -type sendMessageRequest struct { +type SendMessageRequest struct { MessageType string `json:"msgtype,omitempty"` Body string `json:"body,omitempty"` } diff --git a/entities/event/eventController.go b/entities/event/eventController.go index ad89109..9fde86d 100644 --- a/entities/event/eventController.go +++ b/entities/event/eventController.go @@ -2,9 +2,12 @@ package event import ( "bytes" + "context" "encoding/json" + "errors" "fmt" "log" + "math/rand" "net/http" "strconv" "time" @@ -13,8 +16,10 @@ import ( "git.nutfactory.org/hoernschen/Matrix/entities/device" "git.nutfactory.org/hoernschen/Matrix/entities/user" "git.nutfactory.org/hoernschen/Matrix/utils" - "github.com/cenkalti/backoff/v4" + + //"github.com/cenkalti/backoff/v4" "github.com/gorilla/mux" + "github.com/lestrrat-go/backoff" ) func New( @@ -85,7 +90,7 @@ func New( func SendMessageHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") - request := sendMessageRequest{} + request := SendMessageRequest{} errResponse := utils.CheckRequest(r) if errResponse != nil { w.WriteHeader(http.StatusBadRequest) @@ -130,9 +135,7 @@ func SendMessageHandler(w http.ResponseWriter, r *http.Request) { } return } - buf := new(bytes.Buffer) - buf.ReadFrom(r.Body) - content := buf.String() + content, _ := json.Marshal(request) err, newEvent := New( roomId, foundUser.Id, @@ -140,7 +143,7 @@ func SendMessageHandler(w http.ResponseWriter, r *http.Request) { time.Now().Unix(), eventType, foundUser.Id, - content, + string(content), txnId, ) if err != nil { @@ -173,13 +176,19 @@ func SendMessageHandler(w http.ResponseWriter, r *http.Request) { return } for _, server := range servers { - operation := func() error { - return SendTransaction(transaction, server) + if server != config.Homeserver { + log.Printf("Send Transaction to %s", server) + /* + 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) + */ + go retryTransaction(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) - } - go backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify) } response := createEventResponse{ EventId: newEvent.Id, @@ -190,6 +199,20 @@ func SendMessageHandler(w http.ResponseWriter, r *http.Request) { } } +func retryTransaction(transactionToSend *Transaction, server string, httpString string, authCheck bool) (err error) { + b, cancel := config.BackoffPolicy.Start(context.Background()) + defer cancel() + + for backoff.Continue(b) { + err := SendTransaction(transactionToSend, server, httpString, authCheck) + if err == nil { + return nil + } + } + err = errors.New("Not able to send transaction") + return +} + func CreateStateEventHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") errResponse := utils.CheckRequest(r) @@ -271,13 +294,14 @@ func CreateStateEventHandler(w http.ResponseWriter, r *http.Request) { return } for _, server := range servers { - operation := func() error { - return SendTransaction(transaction, server) + /*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) } - go backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify) + go backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify)*/ + go retryTransaction(transaction, server, config.HttpString, config.AuthentificationCheck) } response := createEventResponse{ @@ -405,106 +429,98 @@ func GetStateEventHandler(w http.ResponseWriter, r *http.Request) { } func SyncEventsServerHandler(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json; charset=UTF-8") - 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 - } - errResponse = utils.CheckAuthHeader(r) - if errResponse != nil { - w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(errResponse); 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) - txnId := vars["txnId"] - if txnId == "" { - w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil { - panic(err) - } - return - } - response := syncEventsServerResponse{ - PDUs: make(map[string]pduProcessingResult), - } - 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) + 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 } - foundEvent, err := ReadEvent(pdu.Id) - if foundEvent == nil && err == nil { - err = CreateEvent(pdu, txnId) - } + _ = 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 { - response.PDUs[pdu.Id] = pduProcessingResult{ProcessingError: fmt.Sprintf("Database Error: %s", err)} - continue - } - - err = HandleEvent(pdu) - if err != nil { - response.PDUs[pdu.Id] = pduProcessingResult{ProcessingError: fmt.Sprintf("Error in Event-Handling: %s", err)} - continue - } - - response.PDUs[pdu.Id] = pduProcessingResult{} - } - - if len(missingEventIds) > 0 { - for roomId, eventIds := range missingEventIds { - operation := func() error { - return Backfill(eventIds, roomId, request.Origin) + 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) } - notify := func(err error, duration time.Duration) { - log.Printf("Error Backfill, retrying in %s: %s", duration/1000000000, err) - } - go backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify) + return } - } + 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 + } + response := syncEventsServerResponse{ + PDUs: make(map[string]pduProcessingResult), + } + 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) + } + } - w.WriteHeader(http.StatusOK) - if err := json.NewEncoder(w).Encode(response); err != nil { - panic(err) + err = HandleEvent(pdu, txnId) + if err != nil { + response.PDUs[pdu.Id] = pduProcessingResult{ProcessingError: fmt.Sprintf("Error in Event-Handling: %s", err)} + continue + } + + response.PDUs[pdu.Id] = pduProcessingResult{} + } + + if len(missingEventIds) > 0 { + for roomId, eventIds := range missingEventIds { + Backfill(eventIds, roomId, request.Origin, config.HttpString, config.AuthentificationCheck) + } + } + + w.WriteHeader(http.StatusOK) + if err := json.NewEncoder(w).Encode(response); err != nil { + panic(err) + } + } else { + log.Println("Blocking Response") } } func BackfillHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") - errResponse := utils.CheckAuthHeader(r) + errResponse := utils.CheckAuthHeader(r, "") if errResponse != nil { w.WriteHeader(http.StatusBadRequest) @@ -526,7 +542,6 @@ func BackfillHandler(w http.ResponseWriter, r *http.Request) { limit := 50 eventIds, ok := r.URL.Query()["v"] - log.Printf("%s", eventIds) if !ok || eventIds[0] == "" { w.WriteHeader(http.StatusBadRequest) if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil { @@ -544,11 +559,7 @@ func BackfillHandler(w http.ResponseWriter, r *http.Request) { for _, eventId := range eventIds { foundEvent, err := ReadEvent(eventId) if err != nil || foundEvent == nil { - w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Event not found"}); err != nil { - panic(err) - } - return + continue } for newEventId, _ := range foundEvent.PrevEventHashes { @@ -569,8 +580,8 @@ func BackfillHandler(w http.ResponseWriter, r *http.Request) { } } -func SendTransaction(transaction *Transaction, homeserver string) (err error) { - requestUrl := fmt.Sprintf("https://%s/_matrix/federation/v1/send/%s?", homeserver, transaction.Id) +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) request := syncEventsServerRequest{ Origin: transaction.Origin, Timestamp: transaction.Timestamp, @@ -580,24 +591,66 @@ func SendTransaction(transaction *Transaction, homeserver string) (err error) { if err != nil { return } - client := &http.Client{} + client := &http.Client{Timeout: 2 * time.Second} req, err := http.NewRequest(http.MethodPut, requestUrl, bytes.NewBuffer(reqBody)) if err != nil { return } - _, err = client.Do(req) + 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 + } + } return } -func Backfill(eventIds []string, roomId string, homeserver string) (err error) { - requestUrl := fmt.Sprintf("https://%s/_matrix/federation/v1/backfill/%s?", homeserver, roomId) +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) for _, eventId := range eventIds { requestUrl = fmt.Sprintf("%sv=%s&", requestUrl, eventId) } - r, err := http.Get(requestUrl) + client := &http.Client{Timeout: 2 * time.Second} + var req *http.Request + req, err = http.NewRequest(http.MethodGet, requestUrl, bytes.NewBuffer(nil)) if err != nil { return } + 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) + } response := backfillResponse{} defer r.Body.Close() decoder := json.NewDecoder(r.Body) @@ -622,7 +675,6 @@ func Backfill(eventIds []string, roomId string, homeserver string) (err error) { if !authEventsValid || err != nil { log.Printf("Wrong Auth Events for Event %s", pdu.Id) missingEventIds = append(missingEventIds, pdu.Id) - continue } missingParentIds, err := CheckParents(pdu) if len(missingParentIds) > 0 || err != nil { @@ -630,14 +682,8 @@ func Backfill(eventIds []string, roomId string, homeserver string) (err error) { missingEventIds = append(missingEventIds, parentId) } } - foundEvent, err := ReadEvent(pdu.Id) - if foundEvent == nil && err == nil { - err = CreateEvent(pdu, "") - } - if err != nil { - continue - } - err = HandleEvent(pdu) + + err = HandleEvent(pdu, "") if err != nil { log.Printf("Error in Event-Handling: %s", err) continue @@ -645,7 +691,7 @@ func Backfill(eventIds []string, roomId string, homeserver string) (err error) { } if len(missingEventIds) > 0 { - Backfill(missingEventIds, roomId, homeserver) + Backfill(missingEventIds, roomId, homeserver, config.HttpString, config.AuthentificationCheck) } return @@ -656,6 +702,9 @@ func generateEventId(id string) string { } func GetAuthChain(newEvent *Event) (authChain []*Event, err error) { + if !config.AuthentificationCheck { + return + } createEvent, err := ReadStateEvent(newEvent.RoomId, "m.room.create", "") if err != nil { return @@ -698,7 +747,6 @@ func GetAuthChain(newEvent *Event) (authChain []*Event, err error) { func GetAuthEvents(newEvent *Event) (authEventHashes map[string]EventHash, err error) { authEventHashes = make(map[string]EventHash) - authChain, err := GetAuthChain(newEvent) if err != nil { return @@ -730,10 +778,12 @@ func CheckEventHash(id string, hash EventHash) (correct bool, eventFound bool, e } func CheckParents(eventToCheck *Event) (missingParentIds []string, err error) { - for key, hash := range eventToCheck.PrevEventHashes { - correctHash, foundEvent, err := CheckEventHash(key, hash) - if !correctHash || !foundEvent || err != nil { - missingParentIds = append(missingParentIds, key) + if config.Consensus { + for key, hash := range eventToCheck.PrevEventHashes { + correctHash, foundEvent, err := CheckEventHash(key, hash) + if !correctHash || !foundEvent || err != nil { + missingParentIds = append(missingParentIds, key) + } } } return @@ -741,13 +791,16 @@ func CheckParents(eventToCheck *Event) (missingParentIds []string, err error) { func CheckAuthEvents(eventToCheck *Event) (correct bool, err error) { correct = true + if !config.AuthentificationCheck { + return + } authEvents, err := GetAuthEvents(eventToCheck) if err != nil { return } for key, hash := range authEvents { if eventToCheck.AuthEventHashes[key].SHA256 != hash.SHA256 { - correct = false + //correct = false return } } @@ -755,6 +808,10 @@ func CheckAuthEvents(eventToCheck *Event) (correct bool, err error) { } func CheckSignature(eventToCheck Event) (correct bool) { + if !config.Signing { + correct = true + return + } correct = false signatures := eventToCheck.Signatures eventToCheck.Unsigned = UnsignedData{} @@ -763,32 +820,33 @@ func CheckSignature(eventToCheck Event) (correct bool) { if err != nil { return } - for id, signature := range signatures[eventToCheck.Sender] { - key, err := device.ReadKey(id) - if err == nil { - correct = utils.VerifySignature([]byte(key.Key), jsonString, []byte(signature)) + 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) } } return } -func HandleEvents(events []*Event) (err error) { +func HandleEvents(events []*Event, txnId string) (err error) { for _, eventToHandle := range events { - err = HandleEvent(eventToHandle) + err = HandleEvent(eventToHandle, txnId) } return } -func HandleEvent(eventToHandle *Event) (err error) { +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 + } if eventToHandle.EventType == "m.room.message" { - message := sendMessageRequest{} - err = json.Unmarshal([]byte(eventToHandle.Content), &message) - if err != nil { - return - } - if message.MessageType != "" && message.MessageType == "m.text" { - log.Printf("%s: %s", eventToHandle.Sender, message.Body) - } + log.Printf("%s: %s", eventToHandle.Sender, eventToHandle.Content) } else if eventToHandle.EventType == "m.room.member" { message := MemberEventContent{} err = json.Unmarshal([]byte(eventToHandle.Content), &message) @@ -796,7 +854,11 @@ func HandleEvent(eventToHandle *Event) (err error) { return } if message.Membership == "join" { - CreateRoomMember(eventToHandle.RoomId, eventToHandle.StateKey) + log.Printf("Join %s to Room %s", eventToHandle.StateKey, eventToHandle.RoomId) + } + err = CreateRoomMember(eventToHandle.RoomId, eventToHandle.StateKey, eventToHandle.Origin) + if err != nil { + return } } return diff --git a/entities/event/eventDatabaseConnector.go b/entities/event/eventDatabaseConnector.go index ade8e70..39c3153 100644 --- a/entities/event/eventDatabaseConnector.go +++ b/entities/event/eventDatabaseConnector.go @@ -2,12 +2,11 @@ package event import ( "fmt" - "strings" "git.nutfactory.org/hoernschen/Matrix/utils/database" ) -func CreateRoomMember(roomId string, userId string) (err error) { +func CreateRoomMember(roomId string, userId string, server string) (err error) { sqlStmt := fmt.Sprintf(`INSERT INTO roomMember (roomId, userId, server) VALUES @@ -24,8 +23,9 @@ func CreateRoomMember(roomId string, userId string) (err error) { } defer stmt.Close() - _, err = stmt.Exec(roomId, userId, strings.Split(userId, ":")[1]) + _, err = stmt.Exec(roomId, userId, server) if err != nil { + tx.Rollback() return } tx.Commit() @@ -55,6 +55,7 @@ func CreateParents(eventId string, parentIds map[string]EventHash) (err error) { parentId, ) if err != nil { + tx.Rollback() return } } @@ -87,6 +88,7 @@ func CreateAuthEvents(eventId string, authEventIds map[string]EventHash) (err er authEventId, ) if err != nil { + tx.Rollback() return } } @@ -133,6 +135,7 @@ func CreateEvent(event *Event, txnId string) (err error) { signatures, ) if err != nil { + tx.Rollback() return } tx.Commit() @@ -188,6 +191,7 @@ func CreateEventsFromTransaction(txnId string, pdus map[string]*Event) (err erro signatures, ) if err != nil { + tx.Rollback() return } @@ -385,7 +389,7 @@ func ReadAuthEvents(eventId string) (authEvents map[string]EventHash, err error) } func ReadEvent(id string) (foundEvent *Event, err error) { - queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature + queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature FROM event WHERE id = '%s'`, id) @@ -406,6 +410,7 @@ func ReadEvent(id string) (foundEvent *Event, err error) { &foundEvent.Origin, &foundEvent.Timestamp, &foundEvent.EventType, + &foundEvent.StateKey, &foundEvent.Content, &foundEvent.Depth, &foundEvent.Hashes.SHA256, @@ -435,14 +440,14 @@ func ReadEvent(id string) (foundEvent *Event, err error) { } func ReadStateEvent(roomId string, eventType string, stateKey string) (foundEvent *Event, err error) { - queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature + queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature FROM event WHERE roomId = '%s' AND eventType = '%s' AND stateKey = '%s'`, roomId, eventType, stateKey) if stateKey == "" { - queryStmt = fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature + queryStmt = fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature FROM event WHERE roomId = '%s' AND eventType = '%s'`, roomId, eventType) @@ -465,6 +470,7 @@ func ReadStateEvent(roomId string, eventType string, stateKey string) (foundEven &foundEvent.Origin, &foundEvent.Timestamp, &foundEvent.EventType, + &foundEvent.StateKey, &foundEvent.Content, &foundEvent.Depth, &foundEvent.Hashes.SHA256, @@ -494,7 +500,7 @@ func ReadStateEvent(roomId string, eventType string, stateKey string) (foundEven } func ReadStateEvents(roomId string, eventType string) (foundEvents []*Event, err error) { - queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature + queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature FROM event WHERE roomId = '%s' AND eventType = '%s'`, roomId, eventType) @@ -516,6 +522,7 @@ func ReadStateEvents(roomId string, eventType string) (foundEvents []*Event, err &foundEvent.Origin, &foundEvent.Timestamp, &foundEvent.EventType, + &foundEvent.StateKey, &foundEvent.Content, &foundEvent.Depth, &foundEvent.Hashes.SHA256, @@ -547,7 +554,7 @@ func ReadStateEvents(roomId string, eventType string) (foundEvents []*Event, err } func ReadEventsFromRoom(roomId string) (events map[string]*Event, err error) { - queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature + queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature FROM event WHERE roomId = '%s'`, roomId) @@ -570,6 +577,7 @@ func ReadEventsFromRoom(roomId string) (events map[string]*Event, err error) { &foundEvent.Origin, &foundEvent.Timestamp, &foundEvent.EventType, + &foundEvent.StateKey, &foundEvent.Content, &foundEvent.Depth, &foundEvent.Hashes.SHA256, @@ -601,7 +609,7 @@ func ReadEventsFromRoom(roomId string) (events map[string]*Event, err error) { } func ReadStateEventsFromRoom(roomId string) (events []*Event, err error) { - queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature + queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature FROM event WHERE eventType <> 'm.room.message' AND roomId = '%s'`, roomId) @@ -622,6 +630,7 @@ func ReadStateEventsFromRoom(roomId string) (events []*Event, err error) { &foundEvent.Origin, &foundEvent.Timestamp, &foundEvent.EventType, + &foundEvent.StateKey, &foundEvent.Content, &foundEvent.Depth, &foundEvent.Hashes.SHA256, @@ -653,7 +662,7 @@ func ReadStateEventsFromRoom(roomId string) (events []*Event, err error) { } func ReadEventsFromTransaction(txnId string) (events []*Event, err error) { - queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature + queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature FROM event WHERE txnId = '%s'`, txnId) @@ -674,6 +683,7 @@ func ReadEventsFromTransaction(txnId string) (events []*Event, err error) { &foundEvent.Origin, &foundEvent.Timestamp, &foundEvent.EventType, + &foundEvent.StateKey, &foundEvent.Content, &foundEvent.Depth, &foundEvent.Hashes.SHA256, @@ -727,6 +737,7 @@ func UpdateEvent(event *Event) (err error) { event.Id, ) if err != nil { + tx.Rollback() return } @@ -743,8 +754,9 @@ func DeleteEvent(id string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } @@ -771,8 +783,9 @@ func DeleteParents(eventId string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } @@ -789,8 +802,9 @@ func DeleteAuthEvents(eventId string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } diff --git a/entities/event/transactionDatabaseConnector.go b/entities/event/transactionDatabaseConnector.go index 09cba20..1b68ad3 100644 --- a/entities/event/transactionDatabaseConnector.go +++ b/entities/event/transactionDatabaseConnector.go @@ -25,6 +25,7 @@ func CreateTransaction(transaction *Transaction) (err error) { _, err = stmt.Exec(transaction.Id, transaction.Origin, transaction.Timestamp) if err != nil { + tx.Rollback() return } tx.Commit() @@ -74,6 +75,7 @@ func UpdateTransaction(transaction *Transaction) (err error) { _, err = stmt.Exec(transaction.Origin, transaction.Timestamp, transaction.Id) if err != nil { + tx.Rollback() return } @@ -90,8 +92,9 @@ func DeleteTransaction(id string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } diff --git a/entities/general/generalController.go b/entities/general/generalController.go index 5fd3362..4fdd5c8 100644 --- a/entities/general/generalController.go +++ b/entities/general/generalController.go @@ -6,6 +6,7 @@ import ( "log" "net/http" "os" + "time" "git.nutfactory.org/hoernschen/Matrix/config" "git.nutfactory.org/hoernschen/Matrix/entities/device" @@ -26,12 +27,13 @@ type serverImplementation struct { Version string `json:"version,omitempty"` } -type ResetBody struct { - Packetloss float32 `json:"packetloss,omitempty"` - UnavailableTill int `json:"unavailableTill,omitempty"` - AuthentificationCheck bool `json:"authentificationCheck,omitempty"` - Signing bool `json:"signing,omitempty"` - Encryption bool `json:"encryption,omitempty"` +type SetParamBody struct { + Packetloss int `json:"packetloss,omitempty"` + UnavailableTill int64 `json:"unavailableTill,omitempty"` + Consensus bool `json:"consensus,omitempty"` + AuthentificationCheck bool `json:"authentificationCheck,omitempty"` + Signing bool `json:"signing,omitempty"` + Encryption bool `json:"encryption,omitempty"` } func ResolveServerName(w http.ResponseWriter, r *http.Request) { @@ -52,10 +54,9 @@ func GetServerImplementation(w http.ResponseWriter, r *http.Request) { } } -// TODO: Add a function to set the Config-Params -func Reset(w http.ResponseWriter, r *http.Request) { +func SetParams(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") - request := ResetBody{} + request := SetParamBody{} errResponse := utils.CheckRequest(r) if errResponse != nil { w.WriteHeader(http.StatusBadRequest) @@ -74,22 +75,45 @@ func Reset(w http.ResponseWriter, r *http.Request) { return } + config.Packetloss = request.Packetloss + config.UnavailableTill = request.UnavailableTill + config.Consensus = request.Consensus + config.AuthentificationCheck = request.AuthentificationCheck + config.Signing = request.Signing + config.Encryption = request.Signing + config.HttpString = "https" + if !config.Encryption { + config.HttpString = "http" + } + + w.WriteHeader(http.StatusOK) +} + +func Reset(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 + } + if err := device.InitServerSigningKey(); err != nil { log.Fatal(err) } config.VerifyKeys = make(map[string]map[string][]byte) - os.Remove("sqlite.db") + if err := os.Remove("sqlite.db"); err != nil { + log.Println(err) + } - if err := database.InitDB("sqlite.db"); err != nil { + if err := database.InitDB(fmt.Sprintf("sqlite%s.db", time.Now().Unix())); err != nil { log.Fatal(err) } - config.Packetloss = request.Packetloss - config.UnavailableTill = request.UnavailableTill - config.AuthentificationCheck = request.AuthentificationCheck - config.Signing = request.Signing - config.Encryption = request.Signing + config.SetDefaultParams() w.WriteHeader(http.StatusOK) } diff --git a/entities/room/room.go b/entities/room/room.go index 9f0c363..e5d6f7b 100644 --- a/entities/room/room.go +++ b/entities/room/room.go @@ -34,8 +34,6 @@ type CreateRoomResponse struct { RoomId string `json:"room_id,omitempty"` } -type getRoomMemberRequest struct{} - type getRoomMemberResponse struct { Chunk []*event.Event `json:"chunk,omitempty"` } @@ -48,12 +46,6 @@ type JoinRoomUserResponse struct { RoomId string `json:"room_id,omitempty"` } -type leaveRoomUserRequest struct{} - -type leaveRoomUserResponse struct{} - -type makeJoinRequest struct{} - type makeJoinResponse struct { RoomVersion string `json:"room_version,omitempty"` Event event.Event `json:"event,omitempty"` @@ -74,14 +66,6 @@ type joinRoomServerResponse struct { State []*event.Event `json:"state,omitempty"` } -type makeLeaveRequest struct{} - -type makeLeaveResponse struct{} - -type leaveRoomServerRequest struct{} - -type leaveRoomServerResponse struct{} - type invite3pid struct { IdServer string `json:"id_server,omitempty"` IdAccessToken string `json:"id_access_token,omitempty"` @@ -105,10 +89,8 @@ type invite struct { } type thirdPartySigned struct { - Sender string `json:"sender,omitempty"` - MXID string `json:"mxid,omitempty"` - Signatures signatures `json:"signatures,omitempty"` - Token string `json:"token,omitempty"` + Sender string `json:"sender,omitempty"` + MXID string `json:"mxid,omitempty"` + Signatures map[string]map[string]string `json:"signatures,omitempty"` + Token string `json:"token,omitempty"` } - -type signatures struct{} diff --git a/entities/room/roomController.go b/entities/room/roomController.go index 4b52810..6def007 100644 --- a/entities/room/roomController.go +++ b/entities/room/roomController.go @@ -324,7 +324,6 @@ func CreateRoomHandler(w http.ResponseWriter, r *http.Request) { func GetRoomMemberHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") - request := getRoomMemberRequest{} errResponse := utils.CheckRequest(r) if errResponse != nil { w.WriteHeader(http.StatusBadRequest) @@ -349,16 +348,6 @@ func GetRoomMemberHandler(w http.ResponseWriter, r *http.Request) { } 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"] if roomId == "" { @@ -407,7 +396,7 @@ func JoinRoomUserHandler(w http.ResponseWriter, r *http.Request) { 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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Could not parse JSON Request: %s", err)}); err != nil { panic(err) } return @@ -416,7 +405,7 @@ func JoinRoomUserHandler(w http.ResponseWriter, r *http.Request) { roomId := vars["roomId"] if roomId == "" { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "JoinRoomUserHandler Missing Parameter"}); err != nil { panic(err) } return @@ -424,49 +413,46 @@ func JoinRoomUserHandler(w http.ResponseWriter, r *http.Request) { foundRoom, err := ReadRoom(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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Database Error ReadRoom: %s", err)}); err != nil { panic(err) } return } var joinEvent *event.Event if foundRoom == nil { - memberEventContent := event.MemberEventContent{ - DisplayName: foundUser.Name, - IsDirect: true, - Membership: "join", - } - memberEventContentBytes, _ := json.Marshal(memberEventContent) - err, memberEvent := event.New( - roomId, - foundUser.Id, - config.Homeserver, - time.Now().Unix(), - "m.room.member", - foundUser.Id, - string(memberEventContentBytes), - "", - ) - if err == nil { - err = event.CreateEvent(memberEvent, "") + server := strings.Split(roomId, ":")[1] + requestUrl := fmt.Sprintf("%s://%s/_matrix/federation/v1/make_join/%s/%s", config.HttpString, server, roomId, foundUser.Id) + client := &http.Client{Timeout: 2 * time.Second} + var req *http.Request + req, err = http.NewRequest(http.MethodGet, requestUrl, bytes.NewBuffer(nil)) + if err != nil { + return } + req.Header["Content-Type"] = []string{"application/json"} + res, err := client.Do(req) if err != nil { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Error Event-Creation: %s", err)}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Error Getting Response Make JSON: %s", err)}); err != nil { panic(err) } return } - httpString := "https" - server := strings.Split(roomId, ":")[1] - requestUrl := fmt.Sprintf("%s://%s/_matrix/federation/v1/make_join/%s/%s", httpString, server, roomId, foundUser.Id) - res, err := http.Get(requestUrl) + if res.StatusCode != http.StatusOK { + errResponse = utils.HandleHTTPError(res) + if errResponse != nil { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(errResponse); err != nil { + panic(err) + } + return + } + } makeJoinRes := makeJoinResponse{} decoder = json.NewDecoder(res.Body) err = decoder.Decode(&makeJoinRes) 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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Could not parse JSON makeJoinResponse: %s", err)}); err != nil { panic(err) } return @@ -474,7 +460,7 @@ func JoinRoomUserHandler(w http.ResponseWriter, r *http.Request) { err = CreateRoom(&Room{Id: roomId, Version: makeJoinRes.RoomVersion}) if err != nil { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Database Error: %s", err)}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Database Error CreateRoom: %s", err)}); err != nil { panic(err) } return @@ -489,62 +475,80 @@ func JoinRoomUserHandler(w http.ResponseWriter, r *http.Request) { makeJoinRes.Event.Content, "", ) - requestUrl = fmt.Sprintf("%s://%s/_matrix/federation/v2/send_join/%s/%s", httpString, server, roomId, joinEvent.Id) + requestUrl = fmt.Sprintf("%s://%s/_matrix/federation/v2/send_join/%s/%s", config.HttpString, server, roomId, joinEvent.Id) reqBody, err := json.Marshal(joinEvent) if err != nil { return } - client := &http.Client{} - req, err := http.NewRequest(http.MethodPut, requestUrl, bytes.NewBuffer(reqBody)) + client = &http.Client{Timeout: 2 * time.Second} + req, err = http.NewRequest(http.MethodPut, requestUrl, bytes.NewBuffer(reqBody)) if err != nil { return } + req.Header["Content-Type"] = []string{"application/json"} res, err = client.Do(req) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Error Getting Response Send Join: %s", err)}); err != nil { + panic(err) + } + return + } + if res.StatusCode != http.StatusOK { + errResponse = utils.HandleHTTPError(res) + if errResponse != nil { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(errResponse); err != nil { + panic(err) + } + return + } + } joinRes := joinRoomServerResponse{} decoder = json.NewDecoder(res.Body) err = decoder.Decode(&joinRes) 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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Could not parse JSON joinRoomServerResponse: %s", err)}); err != nil { panic(err) } return } - err = event.HandleEvents(joinRes.State) + err = event.HandleEvents(joinRes.State, "") if err != nil { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Error Handling Events: %s", err)}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Error Handling Events: %s", err)}); err != nil { panic(err) } return } - } else { - memberEventContent := event.MemberEventContent{ - DisplayName: foundUser.Name, - IsDirect: true, - Membership: "join", - } - memberEventContentBytes, _ := json.Marshal(memberEventContent) - err, joinEvent = event.New( - roomId, - foundUser.Id, - config.Homeserver, - time.Now().Unix(), - "m.room.member", - foundUser.Id, - string(memberEventContentBytes), - "", - ) } + memberEventContent := event.MemberEventContent{ + DisplayName: foundUser.Name, + IsDirect: true, + Membership: "join", + } + memberEventContentBytes, _ := json.Marshal(memberEventContent) + err, joinEvent = event.New( + roomId, + foundUser.Id, + config.Homeserver, + time.Now().Unix(), + "m.room.member", + foundUser.Id, + string(memberEventContentBytes), + "", + ) err, txnId := utils.CreateUUID() err = event.CreateEvent(joinEvent, 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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Database Error CreateEvent: %s", err)}); err != nil { panic(err) } return } + event.HandleEvent(joinEvent, "") transaction := &event.Transaction{ Id: txnId, Origin: config.Homeserver, @@ -554,30 +558,33 @@ func JoinRoomUserHandler(w http.ResponseWriter, r *http.Request) { servers, err := event.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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Database Error ReadServers: %s", err)}); err != nil { panic(err) } return } for _, server := range servers { - //if server != config.Homeserver { - operation := func() error { - return event.SendTransaction(transaction, server) + if server != config.Homeserver { + log.Printf("Send Transaction to %s", server) + operation := func() error { + return event.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) } - notify := func(err error, duration time.Duration) { - log.Printf("Error Sending Transaction, retrying in %ss: %s", duration/1000000000, err) - } - go backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify) - //} } - err = CreateRoomMember(roomId, foundUser.Id) - 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) + /* + err = CreateRoomMember(roomId, foundUser.Id, config.Homeserver) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomUserHandler Database Error CreateRoomMember: %s", err)}); err != nil { + panic(err) + } + return } - return - } + */ response := JoinRoomUserResponse{RoomId: roomId} w.WriteHeader(http.StatusOK) if err := json.NewEncoder(w).Encode(response); err != nil { @@ -587,7 +594,6 @@ func JoinRoomUserHandler(w http.ResponseWriter, r *http.Request) { func GetPrepInfoToJoinHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") - request := makeJoinRequest{} errResponse := utils.CheckRequest(r) if errResponse != nil { w.WriteHeader(http.StatusBadRequest) @@ -596,21 +602,12 @@ func GetPrepInfoToJoinHandler(w http.ResponseWriter, r *http.Request) { } 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"] userId := vars["userId"] if roomId == "" || userId == "" { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "GetPrepInfoToJoinHandler Missing Parameter"}); err != nil { panic(err) } return @@ -618,7 +615,7 @@ func GetPrepInfoToJoinHandler(w http.ResponseWriter, r *http.Request) { homeserver := strings.Split(userId, ":") if len(homeserver) <= 1 { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Homeserver in UserId"}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "GetPrepInfoToJoinHandler Missing Homeserver in UserId"}); err != nil { panic(err) } return @@ -639,7 +636,7 @@ func GetPrepInfoToJoinHandler(w http.ResponseWriter, r *http.Request) { memberEventContentBytes, err := json.Marshal(memberEventContent) 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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("GetPrepInfoToJoinHandler Could not parse JSON memberEventContent: %s", err)}); err != nil { panic(err) } return @@ -662,7 +659,6 @@ func GetPrepInfoToJoinHandler(w http.ResponseWriter, r *http.Request) { } } -// TODO: TEST func JoinRoomServerHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") request := event.Event{} @@ -678,7 +674,7 @@ func JoinRoomServerHandler(w http.ResponseWriter, r *http.Request) { 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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomServerHandler Could not parse JSON Request: %s", err)}); err != nil { panic(err) } return @@ -688,7 +684,7 @@ func JoinRoomServerHandler(w http.ResponseWriter, r *http.Request) { eventId := vars["eventId"] if roomId == "" || eventId == "" { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "JoinRoomServerHandler Missing Parameter"}); err != nil { panic(err) } return @@ -708,32 +704,14 @@ func JoinRoomServerHandler(w http.ResponseWriter, r *http.Request) { err = json.Unmarshal([]byte(request.Content), &memberEventContent) 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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomServerHandler Could not parse JSON MemberEventContent: %s", err)}); err != nil { panic(err) } return } if memberEventContent.Membership != "join" { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Wrong Membership"}); err != nil { - panic(err) - } - return - } - if err == nil { - err = event.CreateEvent(&request, "") - } - if err != nil { - w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Error Event-Creation: %s", err)}); err != nil { - panic(err) - } - return - } - CreateRoomMember(roomId, request.StateKey) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Database Error: %s", err)}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "JoinRoomServerHandler Wrong Membership"}); err != nil { panic(err) } return @@ -741,7 +719,7 @@ func JoinRoomServerHandler(w http.ResponseWriter, r *http.Request) { authChain, err := event.GetAuthChain(&request) if err != nil { w.WriteHeader(http.StatusBadRequest) - if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Error Creating Auth Chain: %s", err)}); err != nil { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomServerHandler Error Creating Auth Chain: %s", err)}); err != nil { panic(err) } return @@ -749,7 +727,7 @@ func JoinRoomServerHandler(w http.ResponseWriter, r *http.Request) { stateEvents, err := event.ReadStateEventsFromRoom(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 { + if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("JoinRoomServerHandler Database Error ReadStateEventsFromRoom: %s", err)}); err != nil { panic(err) } return diff --git a/entities/room/roomDatabaseConnector.go b/entities/room/roomDatabaseConnector.go index aba049d..7dd944f 100644 --- a/entities/room/roomDatabaseConnector.go +++ b/entities/room/roomDatabaseConnector.go @@ -3,6 +3,7 @@ package room import ( "fmt" + "git.nutfactory.org/hoernschen/Matrix/config" "git.nutfactory.org/hoernschen/Matrix/entities/event" "git.nutfactory.org/hoernschen/Matrix/utils/database" ) @@ -34,17 +35,18 @@ func CreateRoom(room *Room) (err error) { room.Federated, ) if err != nil { + tx.Rollback() return } tx.Commit() for _, userId := range room.Members { - err = CreateRoomMember(room.Id, userId) + err = CreateRoomMember(room.Id, userId, config.Homeserver) } return } -func CreateRoomMember(roomId string, userId string) (err error) { - return event.CreateRoomMember(roomId, userId) +func CreateRoomMember(roomId string, userId string, server string) (err error) { + return event.CreateRoomMember(roomId, userId, server) } func ReadRoom(id string) (foundRoom *Room, err error) { @@ -121,6 +123,7 @@ func UpdateRoom(room *Room) (err error) { room.Id, ) if err != nil { + tx.Rollback() return } @@ -137,8 +140,9 @@ func DeleteRoom(id string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } @@ -157,8 +161,9 @@ func DeleteRoomMember(roomId string, userId string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } @@ -175,8 +180,9 @@ func DeleteAllRoomMemberForUser(userId string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } @@ -193,8 +199,9 @@ func DeleteAllRoomMemberForRoom(roomId string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } diff --git a/entities/user/user.go b/entities/user/user.go index 78d23ea..1843066 100644 --- a/entities/user/user.go +++ b/entities/user/user.go @@ -31,7 +31,7 @@ type RegisterRequest struct { type RegisterResponse struct { UserId string `json:"user_id,omitempty"` AccessToken string `json:"access_token,omitempty"` - HomeServer string `json:"home_server,omitempty"` + sqllite string `json:"home_server,omitempty"` DeviceId string `json:"device_id,omitempty"` } diff --git a/entities/user/userDatabaseConnector.go b/entities/user/userDatabaseConnector.go index 460f7de..5bd639f 100644 --- a/entities/user/userDatabaseConnector.go +++ b/entities/user/userDatabaseConnector.go @@ -26,6 +26,7 @@ func CreateUser(user *User) (err error) { _, err = stmt.Exec(user.Id, user.Name, user.Password) if err != nil { + tx.Rollback() return } tx.Commit() @@ -100,6 +101,7 @@ func UpdateUser(user *User) (err error) { _, err = stmt.Exec(user.Name, user.Password, user.Id) if err != nil { + tx.Rollback() return } @@ -116,8 +118,9 @@ func DeleteUser(id string) (err error) { return } - _, err = database.DB.Exec(queryStmt) + _, err = tx.Exec(queryStmt) if err != nil { + tx.Rollback() return } diff --git a/go.mod b/go.mod index 4ef06af..5043d3e 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,6 @@ go 1.14 require ( github.com/cenkalti/backoff/v4 v4.1.0 github.com/gorilla/mux v1.8.0 + github.com/lestrrat-go/backoff v1.0.0 github.com/mattn/go-sqlite3 v1.14.4 - github.com/urfave/cli v1.22.4 ) diff --git a/go.sum b/go.sum index 25f9c5a..a1175df 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,7 @@ github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= @@ -14,16 +15,22 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lestrrat-go/backoff v1.0.0 h1:nR+UgAhdhwfw2i+xznuHRlj81oMYa7u3lXun0xcsXUU= +github.com/lestrrat-go/backoff v1.0.0/go.mod h1:c7OnDlnHsFXbH1vyIS8+txH+THcc+QFlSQTrJVe4EIM= github.com/mattn/go-sqlite3 v1.14.3 h1:j7a/xn1U6TKA/PHHxqZuzh64CdtRc7rU9M+AvkOl5bA= github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= github.com/mattn/go-sqlite3 v1.14.4 h1:4rQjbDxdu9fSgI/r3KN72G3c2goxknAqHHgPWWs8UlI= github.com/mattn/go-sqlite3 v1.14.4/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= diff --git a/main.go b/main.go index 4631fdb..5ba2bdd 100644 --- a/main.go +++ b/main.go @@ -5,6 +5,7 @@ import ( "log" "net/http" "os" + "time" "git.nutfactory.org/hoernschen/Matrix/config" "git.nutfactory.org/hoernschen/Matrix/entities/device" @@ -14,6 +15,7 @@ import ( "git.nutfactory.org/hoernschen/Matrix/entities/user" "git.nutfactory.org/hoernschen/Matrix/utils/database" "git.nutfactory.org/hoernschen/Matrix/utils/router" + "github.com/lestrrat-go/backoff" ) var keyPath = "./ssl.key" @@ -25,6 +27,7 @@ var routes = router.Routes{ router.Route{"ResolveServerName", "GET", "/.well-known/matrix/server", general.ResolveServerName}, router.Route{"GetServerImplementation", "GET", "/_matrix/federation/v1/version", general.GetServerImplementation}, router.Route{"Reset", "GET", "/reset", general.Reset}, + router.Route{"SetParams", "GET", "/setparams", general.SetParams}, // Keys router.Route{"GetSigningKey", "GET", "/_matrix/key/v2/server/{keyId}", device.GetServerSigningKeyHandler}, @@ -69,31 +72,22 @@ func main() { config.VerifyKeys = make(map[string]map[string][]byte) os.Remove("sqlite.db") + config.BackoffPolicy = backoff.NewExponential( + backoff.WithInterval(500*time.Millisecond), + backoff.WithMaxRetries(16), + ) + if err := database.InitDB("sqlite.db"); err != nil { log.Fatal(err) } defer database.DB.Close() - // TODO: Set Default Config Params here - config.HttpString = "https" + config.SetDefaultParams() router := router.NewRouter(routes) - // TODO: Serve on Port 443 and 80 without Redirect httpErr := http.ListenAndServeTLS(":443", certPath, keyPath, router) if httpErr != nil { log.Fatal(httpErr) } - - // TODO: TEST - httpErr = http.ListenAndServe(":80", router) - if httpErr != nil { - log.Fatal(httpErr) - } - - /* - go http.ListenAndServe(":80", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently) - })) - */ } diff --git a/utils/database/databaseConnector.go b/utils/database/databaseConnector.go index 58dea63..8c9872b 100644 --- a/utils/database/databaseConnector.go +++ b/utils/database/databaseConnector.go @@ -3,7 +3,6 @@ package database import ( "database/sql" "fmt" - "log" _ "github.com/mattn/go-sqlite3" ) @@ -11,7 +10,6 @@ import ( var DB *sql.DB func InitDB(filepath string) (err error) { - log.Printf("Init DB") DB, err = sql.Open("sqlite3", filepath) if err != nil { panic(err) @@ -31,7 +29,6 @@ func InitDB(filepath string) (err error) { } func initDeviceTable() (err error) { - log.Printf("Init Device Table") statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS device ( id TEXT PRIMARY KEY, name TEXT, @@ -43,47 +40,10 @@ func initDeviceTable() (err error) { } statement.Exec() - /* - newDevice := &device.Device{Id: "test", Name: "TEST", Keys: nil} - err = CreateDevice(db, newDevice, "test") - if err != nil { - log.Printf("Error Create: %s", err) - return - } - newDevice.Name = "TEST2" - err = UpdateDevice(db, newDevice) - if err != nil { - log.Printf("Error Update: %s", err) - return - } - devices, err := ReadDevicesForUser(db, "test") - if err != nil { - log.Printf("Error Read User: %s", err) - return - } - log.Println(devices) - err = DeleteDevice(db, newDevice.Id) - if err != nil { - log.Printf("Error Delete: %s", err) - return - } - de, err := ReadDevice(db, "test") - if err != nil { - log.Printf("Error Read: %s", err) - return - } - if de != nil { - log.Printf("Device ID: %s Name: %s", de.Id, de.Name) - } else { - log.Printf("No Device found") - } - */ - return } func initKeyTable() (err error) { - log.Printf("Init Key Table") statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS key ( id TEXT PRIMARY KEY, type TEXT, @@ -94,46 +54,11 @@ func initKeyTable() (err error) { return } statement.Exec() - /* - newKey := &device.Key{Id: "test", Type: "test", Key: "test"} - err = CreateKey(db, newKey, "test") - if err != nil { - log.Printf("Error Create: %s", err) - return - } - keys, err := ReadKeysForDevice(db, "test") - if err != nil { - log.Printf("Error Read Multiple: %s", err) - return - } - log.Println(keys) - newKey.Key = "TEST123" - err = UpdateKey(db, newKey) - if err != nil { - log.Printf("Error Update: %s", err) - return - } - err = DeleteKey(db, newKey.Id) - if err != nil { - log.Printf("Error Delete: %s", err) - return - } - readKey, err := ReadKey(db, "test") - if err != nil { - log.Printf("Error Read: %s", err) - return - } - if readKey != nil { - log.Printf("Key ID: %s Type: %s, Key: %s", readKey.Id, readKey.Type, readKey.Key) - } else { - log.Printf("No Key found") - } - */ + return } func initEventTable() (err error) { - log.Printf("Init Event Table") statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS event ( id TEXT PRIMARY KEY, roomId TEXT, @@ -172,60 +97,11 @@ func initEventTable() (err error) { return } statement.Exec() - /* - newEvent := &event.Event{ - Id: "test", - RoomId: "test", - EventType: "test", - Content: "{TEST}", - ParentId: "test1", - Depth: 0, - } - err = CreateEvent(db, newEvent, "test") - if err != nil { - log.Printf("Error Create: %s", err) - return - } - eventsRoom, err := ReadEventsFromRoom(db, "test") - if err != nil { - log.Printf("Error Read User: %s", err) - return - } - log.Println(eventsRoom) - eventsTxn, err := ReadEventsFromTransaction(db, "test") - if err != nil { - log.Printf("Error Read User: %s", err) - return - } - log.Println(eventsTxn) - newEvent.Content = "{TEST123}" - err = UpdateEvent(db, newEvent) - if err != nil { - log.Printf("Error Update: %s", err) - return - } - err = DeleteEvent(db, newEvent.Id) - if err != nil { - log.Printf("Error Delete: %s", err) - return - } - readEvent, err := ReadEvent(db, "test") - if err != nil { - log.Printf("Error Read: %s", err) - return - } - if readEvent != nil { - log.Printf("Event ID: %s RoomId: %s EventType: %s Content: %s ParentId: %s Depth: %s", - readEvent.Id, readEvent.RoomId, readEvent.EventType, readEvent.Content, readEvent.ParentId, readEvent.Depth) - } else { - log.Printf("No Event found") - } - */ + return } func initRoomTable() (err error) { - log.Printf("Init Room Table") statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS room ( id TEXT PRIMARY KEY, version TEXT, @@ -249,61 +125,11 @@ func initRoomTable() (err error) { return } statement.Exec() - /* - newRoom := &room.Room{Id: "test", Version: "test"} - err = CreateRoom(db, newRoom, "test") - if err != nil { - log.Printf("Error Create: %s", err) - return - } - err = CreateRoomMember(db, newRoom.Id, "test2") - if err != nil { - log.Printf("Error Create: %s", err) - return - } - roomMembers, err := ReadRoomMembers(db, newRoom.Id) - if err != nil { - log.Printf("Error Read Members: %s", err) - return - } - log.Println(roomMembers) - newRoom.Version = "test2" - err = UpdateRoom(db, newRoom) - if err != nil { - log.Printf("Error Update: %s", err) - return - } - err = DeleteRoomMember(db, newRoom.Id, "test") - if err != nil { - log.Printf("Error Delete: %s", err) - return - } - err = DeleteAllRoomMemberForUser(db, "test2") - if err != nil { - log.Printf("Error Delete: %s", err) - return - } - err = DeleteRoom(db, newRoom.Id) - if err != nil { - log.Printf("Error Delete: %s", err) - return - } - readRoom, err := ReadRoom(db, newRoom.Id) - if err != nil { - log.Printf("Error Read: %s", err) - return - } - if readRoom != nil { - log.Printf("Room ID: %s Version: %s Members: %s", readRoom.Id, readRoom.Version, readRoom.Members) - } else { - log.Printf("No Room found") - } - */ + return } func initTransactionTable() (err error) { - log.Printf("Init Transaction Table") statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS txn ( id TEXT PRIMARY KEY, origin TEXT, @@ -314,40 +140,10 @@ func initTransactionTable() (err error) { } statement.Exec() - /* - newTransaction := &transaction.Transaction{Id: "test", Origin: "test.de", Timestamp: 1234} - err = CreateTransaction(db, newTransaction) - if err != nil { - log.Printf("Error Create: %s", err) - return - } - newTransaction.Origin = "test2.de" - err = UpdateTransaction(db, newTransaction) - if err != nil { - log.Printf("Error Update: %s", err) - return - } - err = DeleteTransaction(db, newTransaction.Id) - if err != nil { - log.Printf("Error Delete: %s", err) - return - } - readTransaction, err := ReadTransaction(db, newTransaction.Id) - if err != nil { - log.Printf("Error Read: %s", err) - return - } - if readTransaction != nil { - log.Printf("Transaction ID: %s Origin: %s Timestamp: %s PDUS: %s", readTransaction.Id, readTransaction.Origin, readTransaction.Timestamp, readTransaction.PDUS) - } else { - log.Printf("No Transaction found") - } - */ return } func initUserTable() (err error) { - log.Printf("Init User Table") statement, err := DB.Prepare(`CREATE TABLE IF NOT EXISTS user ( id TEXT PRIMARY KEY, name TEXT, @@ -358,36 +154,6 @@ func initUserTable() (err error) { } statement.Exec() - /* - newUser := &user.User{Id: "test", Name: "test", Password: "test"} - err = CreateUser(db, newUser) - if err != nil { - log.Printf("Error Create: %s", err) - return - } - newUser.Name = "TEST2" - err = UpdateUser(db, newUser) - if err != nil { - log.Printf("Error Update: %s", err) - return - } - err = DeleteUser(db, newUser.Id) - if err != nil { - log.Printf("Error Delete: %s", err) - return - } - readUser, err := ReadUser(db, newUser.Id) - if err != nil { - log.Printf("Error Read: %s", err) - return - } - if readUser != nil { - log.Printf("User ID: %s Name: %s Password: %s Devices: %s", readUser.Id, readUser.Name, readUser.Password, readUser.Devices) - } else { - log.Printf("No User found") - } - */ - return } diff --git a/utils/encryptionService.go b/utils/encryptionService.go index dba281f..7965cef 100644 --- a/utils/encryptionService.go +++ b/utils/encryptionService.go @@ -49,17 +49,26 @@ func GenerateKeyPair() (publicKey ed25519.PublicKey, privateKey ed25519.PrivateK return } -func Sign(message []byte) []byte { - return ed25519.Sign(config.PrivateKey, message) +func Sign(message []byte) string { + signatureBytes := ed25519.Sign(config.PrivateKey, message) + return base64.RawStdEncoding.EncodeToString(signatureBytes) } func SignContent(content []byte) (signatures map[string]map[string]string) { signatures = make(map[string]map[string]string) signatures[config.Homeserver] = make(map[string]string) - signatures[config.Homeserver][config.KeyId] = string(Sign(content)) + if !config.Signing { + return + } + signatures[config.Homeserver][config.KeyId] = Sign(content) return } -func VerifySignature(publicKey []byte, message []byte, signature []byte) bool { - return ed25519.Verify(publicKey, message, signature) +func VerifySignature(publicKey []byte, message []byte, signature string) bool { + signatureBytes, err := base64.RawStdEncoding.DecodeString(signature) + if err != nil { + return false + } + ed25519.Verify(config.PublicKey, message, signatureBytes) + return true } diff --git a/utils/requestChecker.go b/utils/requestChecker.go index 59be75b..c8ad4d1 100644 --- a/utils/requestChecker.go +++ b/utils/requestChecker.go @@ -1,9 +1,9 @@ package utils import ( - "bytes" "encoding/json" "fmt" + "log" "net/http" "strings" @@ -32,7 +32,10 @@ func CheckRequest(r *http.Request) (response *ErrorResponse) { return } -func CheckAuthHeader(r *http.Request) (response *ErrorResponse) { +func CheckAuthHeader(r *http.Request, content string) (response *ErrorResponse) { + if !config.AuthentificationCheck { + return + } authHeader := r.Header.Get("Authorization") if authHeader == "" || !strings.Contains(authHeader, "X-Matrix") { response = &ErrorResponse{ErrorMessage: "Missing Authorization Header"} @@ -40,15 +43,12 @@ func CheckAuthHeader(r *http.Request) (response *ErrorResponse) { } keys := strings.Split(authHeader, ",") origin := strings.Split(keys[0], "=")[1] - if !strings.Contains(keys[2], "ed25519") { + if !strings.Contains(keys[1], "ed25519") { response = &ErrorResponse{ErrorMessage: "Missing ed25519 Signature Key"} return } - key := strings.Split(strings.Replace(strings.Split(keys[2], "=")[1], "\"", "", 2), ":")[1] + key := strings.Split(strings.Replace(strings.Split(keys[1], "=")[1], "\"", "", 2), ":")[1] signature := strings.Replace(strings.Split(keys[2], "=")[1], "\"", "", 2) - buf := new(bytes.Buffer) - buf.ReadFrom(r.Body) - content := buf.String() requestSummary := RequestSummary{ Method: r.Method, Uri: r.RequestURI, @@ -61,7 +61,7 @@ func CheckAuthHeader(r *http.Request) (response *ErrorResponse) { response = &ErrorResponse{ErrorMessage: "Error Creating Auth JSON String"} return } - correct := VerifySignature([]byte(key), requestSummaryString, []byte(signature)) + correct := VerifySignature([]byte(key), requestSummaryString, signature) if !correct { response = &ErrorResponse{ErrorMessage: "Signature in Auth Header is incorrect"} return @@ -81,7 +81,7 @@ func CreateAuthHeader(method string, uri string, destination string, content str if err != nil { return } - authHeader = fmt.Sprintf("X-Matrix origin=%s,key=\"%s\",sig=\"%s\"", config.Homeserver, config.KeyId, Sign(SigningContent)) + authHeader = fmt.Sprintf("X-Matrix origin=%s,key=%s,sig=%s", config.Homeserver, config.KeyId, Sign(SigningContent)) return } @@ -98,6 +98,19 @@ func GetAccessToken(r *http.Request) (token string, response *ErrorResponse) { return } +func HandleHTTPError(res *http.Response) (response *ErrorResponse) { + log.Printf("Statuscode %s", res.Status) + response = &ErrorResponse{} + decoder := json.NewDecoder(res.Body) + err := decoder.Decode(response) + if err != nil { + log.Printf("Error not parseable") + return + } + log.Printf("%s (%s)", response.ErrorMessage, response.ErrorCode) + return +} + func IsJSONString(s string) bool { var js string return json.Unmarshal([]byte(s), &js) == nil diff --git a/workloadGenerator.go b/workloadGenerator.go new file mode 100644 index 0000000..ead2b88 --- /dev/null +++ b/workloadGenerator.go @@ -0,0 +1,626 @@ +package main + +import ( + "bytes" + "crypto/tls" + "encoding/base64" + "encoding/csv" + "encoding/json" + "fmt" + "log" + "math/rand" + "net/http" + "os" + "strconv" + "strings" + "time" + + "git.nutfactory.org/hoernschen/Matrix/entities/event" + "git.nutfactory.org/hoernschen/Matrix/entities/general" + "git.nutfactory.org/hoernschen/Matrix/entities/room" + "git.nutfactory.org/hoernschen/Matrix/entities/user" + "git.nutfactory.org/hoernschen/Matrix/utils" +) + +var BaseLineTest = true + +var systemParamsIndex = 0 + +type SystemParams struct { + Id string + BytesToSend int + MessagesPerSecond float32 + Distribution map[string][]string + Packetloss int + MinutesNotAvailable int + Consensus bool + AuthentificationCheck bool + Signing bool + Encryption bool +} + +var httpString string +var users = []map[string][]string{ + map[string][]string{ + "143.93.38.208": []string{ + "user1", + "user2", + "user3", + "user4", + "user5", + "user6", + }, + }, + map[string][]string{ + "143.93.38.207": []string{ + "user1", + "user2", + "user3", + "user4", + }, + "143.93.38.208": []string{ + "user1", + }, + "143.93.38.209": []string{ + "user1", + }, + }, + map[string][]string{ + "143.93.38.207": []string{ + "user1", + "user2", + "user3", + "user4", + }, + "143.93.38.208": []string{ + "user1", + "user2", + "user3", + "user4", + }, + "143.93.38.209": []string{ + "user1", + "user2", + "user3", + "user4", + }, + }, +} + +var servers = []string{ + "143.93.38.207", + "143.93.38.208", + "143.93.38.209", +} + +var systemParams = []SystemParams{ + SystemParams{ + Id: "111111111", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + /* + SystemParams{ + Id: "011111111", + BytesToSend: 8, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "211111111", + BytesToSend: 512, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "101111111", + BytesToSend: 280, + MessagesPerSecond: 0.1, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "121111111", + BytesToSend: 280, + MessagesPerSecond: 10.0, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "110111111", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[0], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "112111111", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[2], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "111011111", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 0, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "111211111", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 20, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "111121111", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 1, + Consensus: true, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "111110111", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: false, + AuthentificationCheck: true, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "111111011", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: false, + Signing: true, + Encryption: true, + }, + SystemParams{ + Id: "111111101", + BytesToSend: 280, + MessagesPerSecond: 1.0, + Distribution: users[1], + Packetloss: 1, + MinutesNotAvailable: 0, + Consensus: true, + AuthentificationCheck: true, + Signing: false, + Encryption: true, + }, + */ +} + +var userIds []string +var accessTokens map[string]string +var roomId string + +func getCSVWriter(filename string) (writer *csv.Writer) { + file, err := os.Create(fmt.Sprintf("%s %s.csv", strconv.FormatInt(time.Now().Unix(), 10), filename)) + if err != nil { + log.Fatalf("Error Creating CSV: %s", err) + } + defer file.Close() + writer = csv.NewWriter(file) + return +} + +func main() { + http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + httpString = "https" + iteration := 0 + if BaseLineTest { + file, err := os.Create(fmt.Sprintf("%s Baseline Measurement.csv", strconv.FormatInt(time.Now().Unix(), 10))) + if err != nil { + log.Fatalf("Error Creating CSV: %s", err) + } + defer file.Close() + writer := csv.NewWriter(file) + defer writer.Flush() + err = writer.Write([]string{"Iteration", "Start", "End"}) + if err != nil { + log.Fatalf("Error in Writing CSV: %s", err) + } + for iteration < 10 { + log.Printf("Iteration: %s", strconv.Itoa(iteration)) + start := time.Now().Unix() + time.Sleep(2 * time.Minute) + end := time.Now().Unix() + iteration++ + err = writer.Write([]string{strconv.Itoa(iteration), strconv.FormatInt(start, 10), strconv.FormatInt(end, 10)}) + if err != nil { + log.Fatalf("Error in Writing CSV: %s", err) + } + } + } else { + for _, systemParam := range systemParams { + file, err := os.Create(fmt.Sprintf("%s %s Measurement Matrix.csv", strconv.FormatInt(time.Now().Unix(), 10), systemParam.Id)) + if err != nil { + log.Fatalf("Error Creating CSV: %s", err) + } + writer := csv.NewWriter(file) + err = writer.Write([]string{"Iteration", "Start", "End", "Actions Send"}) + if err != nil { + log.Fatalf("Error in Writing CSV: %s", err) + } + millisecondsToWait := 1000 / systemParam.MessagesPerSecond + iteration = 0 + for iteration < 30 { + err := setUp(systemParam) + if err != nil { + log.Fatalf("Error in SetUp: %s", err) + } + b := make([]byte, systemParam.BytesToSend) + _, err = rand.Read(b) + message := base64.RawStdEncoding.EncodeToString(b) + start := time.Now() + end := start.Add(2 * time.Minute).Unix() + log.Printf("Id: %s - Iteration: %s - Start: %s - End: %s", systemParam.Id, strconv.Itoa(iteration), strconv.FormatInt(start.Unix(), 10), strconv.FormatInt(end, 10)) + actionsSend := 0 + for time.Now().Unix() < end { + time.Sleep(time.Duration(millisecondsToWait) * time.Millisecond) + + err = sendMessage(message) + if err != nil { + log.Fatalf("Error sending Message %s", err) + } + + actionsSend++ + } + iteration++ + err = writer.Write([]string{strconv.Itoa(iteration), strconv.FormatInt(start.Unix(), 10), strconv.FormatInt(end, 10), strconv.Itoa(actionsSend)}) + if err != nil { + log.Fatalf("Error in Writing CSV: %s", err) + } + time.Sleep(1 * time.Second) + err = reset() + if err != nil { + log.Fatalf("Error in Reset: %s", err) + } + time.Sleep(1 * time.Second) + } + writer.Flush() + file.Close() + } + } +} + +func sendMessage(message string) (err error) { + userIndex := rand.Intn(3) + userId := userIds[userIndex] + accessToken := accessTokens[userId] + err, txnId := utils.CreateUUID() + if err != nil { + return + } + requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/rooms/%s/send/m.room.message/%s", httpString, strings.Split(userId, ":")[1], roomId, txnId) + request := event.SendMessageRequest{ + MessageType: "m.text", + Body: message, + } + reqBody, err := json.Marshal(request) + if err != nil { + return + } + client := &http.Client{} + var req *http.Request + req, err = http.NewRequest(http.MethodPut, requestUrl, bytes.NewBuffer(reqBody)) + if err != nil { + return + } + req.Header["Content-Type"] = []string{"application/json"} + req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", accessToken)} + res, err := client.Do(req) + if err != nil { + return + } + if res.StatusCode != http.StatusOK { + handleError(res) + } + return +} + +func setParams(systemParamsToUse SystemParams) (err error) { + serverNotAvailableIndex := 1 + for i, server := range servers { + minutesNotAvailable := 0 + if serverNotAvailableIndex == i { + minutesNotAvailable = systemParamsToUse.MinutesNotAvailable + } + requestUrl := fmt.Sprintf("%s://%s/setparams", httpString, server) + request := general.SetParamBody{ + Packetloss: systemParamsToUse.Packetloss, + UnavailableTill: time.Now().Add(time.Duration(minutesNotAvailable) * time.Minute).Unix(), + Consensus: systemParamsToUse.Consensus, + AuthentificationCheck: systemParamsToUse.AuthentificationCheck, + Signing: systemParamsToUse.Signing, + Encryption: systemParamsToUse.Encryption, + } + var reqBody []byte + reqBody, err = json.Marshal(request) + if err != nil { + return + } + client := &http.Client{Timeout: 10 * time.Second} + var req *http.Request + req, err = http.NewRequest(http.MethodGet, requestUrl, bytes.NewBuffer(reqBody)) + if err != nil { + return + } + req.Header["Content-Type"] = []string{"application/json"} + var res *http.Response + res, err = client.Do(req) + if err != nil { + return + } + if res.StatusCode != http.StatusOK { + handleError(res) + } + } + return +} + +func setUp(systemParamsToUse SystemParams) (err error) { + accessTokens = make(map[string]string) + err = createUsers(systemParamsToUse.Distribution) + if err != nil { + log.Printf("Error in User-Creation: %s", err) + return + } + // Create Room + err = createRoom(userIds[0]) + if err != nil { + log.Printf("Error in Room-Creation: %s", err) + return + } + + // Join to Room + err = joinRoom(userIds[1:]) + if err != nil { + log.Printf("Error joining Room: %s", err) + return + } + + err = setParams(systemParamsToUse) + return +} + +func reset() (err error) { + roomId = "" + userIds = []string{} + accessTokens = make(map[string]string) + for _, server := range servers { + requestUrl := fmt.Sprintf("%s://%s/reset", httpString, server) + client := &http.Client{Timeout: 10 * time.Second} + var req *http.Request + req, err = http.NewRequest(http.MethodGet, requestUrl, bytes.NewBuffer(nil)) + if err != nil { + return + } + req.Header["Content-Type"] = []string{"application/json"} + var res *http.Response + res, err = client.Do(req) + if err != nil { + return + } + if res.StatusCode != http.StatusOK { + handleError(res) + } + } + return +} + +func createRoom(userId string) (err error) { + accessToken := accessTokens[userId] + requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/createRoom", httpString, strings.Split(userId, ":")[1]) + request := room.CreateRoomRequest{ + Visibility: "public", + Name: "Testraum", + Topic: "Raum für die Energieeffizienz-Tests", + RoomVersion: "1", + CreationContent: room.CreationContent{ + Federated: true, + }, + Preset: "public_chat", + IsDirect: true, + } + reqBody, err := json.Marshal(request) + if err != nil { + return + } + client := &http.Client{Timeout: 10 * time.Second} + req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody)) + if err != nil { + return + } + req.Header["Content-Type"] = []string{"application/json"} + req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", accessToken)} + res, err := client.Do(req) + if err != nil { + return + } + if res.StatusCode != http.StatusOK { + handleError(res) + } else { + response := room.CreateRoomResponse{} + decoder := json.NewDecoder(res.Body) + err = decoder.Decode(&response) + if err != nil { + return + } + roomId = response.RoomId + log.Printf("Room created: %s", roomId) + } + return +} + +func joinRoom(userIdsToJoin []string) (err error) { + for _, userId := range userIdsToJoin { + err = joinRoomUser(userId) + if err != nil { + return + } + //time.Sleep(time.Duration(1) * time.Second) + } + return +} + +func joinRoomUser(userId string) (err error) { + log.Printf("Join %s to %s", userId, roomId) + accessToken := accessTokens[userId] + requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/rooms/%s/join", httpString, strings.Split(userId, ":")[1], roomId) + request := room.JoinRoomUserRequest{} + reqBody, err := json.Marshal(request) + if err != nil { + return + } + client := &http.Client{Timeout: 10 * time.Second} + req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody)) + if err != nil { + return + } + req.Header["Content-Type"] = []string{"application/json"} + req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", accessToken)} + res, err := client.Do(req) + if err != nil { + return + } + if res.StatusCode != http.StatusOK { + handleError(res) + } else { + response := room.JoinRoomUserResponse{} + decoder := json.NewDecoder(res.Body) + err = decoder.Decode(&response) + if err != nil { + return + } + roomId = response.RoomId + log.Printf("%s joined Room", userId) + } + return +} + +func createUsers(serverUserMap map[string][]string) (err error) { + for server, usersToCreate := range serverUserMap { + for _, userToCreate := range usersToCreate { + var userId string + var accessToken string + userId, accessToken, err = createUser(userToCreate, server) + if err != nil { + return + } + if userId != "" && accessToken != "" { + log.Printf("%s created - AccessToken: %s", userId, accessToken) + accessTokens[userId] = accessToken + userIds = append(userIds, userId) + } + } + } + return +} + +func createUser(userToCreate string, homeserver string) (userId string, accessToken string, err error) { + requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/register", httpString, homeserver) + request := user.RegisterRequest{ + Auth: user.AuthentificationData{ + LoginType: "m.login.password", + }, + Username: userToCreate, + Password: "password", + DeviceName: fmt.Sprintf("%s's device", userToCreate), + } + reqBody, err := json.Marshal(request) + if err != nil { + return + } + client := &http.Client{Timeout: 10 * time.Second} + req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody)) + if err != nil { + return + } + req.Header["Content-Type"] = []string{"application/json"} + res, err := client.Do(req) + if err != nil { + return + } + if res.StatusCode != http.StatusOK { + handleError(res) + } else { + response := user.RegisterResponse{} + decoder := json.NewDecoder(res.Body) + err = decoder.Decode(&response) + if err != nil { + return + } + userId = response.UserId + accessToken = response.AccessToken + } + return +} + +func handleError(res *http.Response) { + utils.HandleHTTPError(res) +} diff --git a/workloadGenerator/workloadGenerator.go b/workloadGenerator/workloadGenerator.go deleted file mode 100644 index 315c221..0000000 --- a/workloadGenerator/workloadGenerator.go +++ /dev/null @@ -1,209 +0,0 @@ -package workloadgenerator - -import ( - "bytes" - "crypto/tls" - "encoding/json" - "fmt" - "log" - "net/http" - "strings" - - "git.nutfactory.org/hoernschen/Matrix/entities/room" - "git.nutfactory.org/hoernschen/Matrix/entities/user" - "git.nutfactory.org/hoernschen/Matrix/utils" -) - -var httpString = "http" -var servers = []string{ - "localhost", -} - -var userIds []string -var accessTokens map[string]string -var roomId string - -var users = []string{ - "user1", - "user2", - "user3", - "user4", - "user5", - "user6", -} - -func main() { - http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - accessTokens = make(map[string]string) - err := createUsers() - if err != nil { - log.Printf("Error in User-Creation: %s", err) - return - } - // Create Room - err = createRoom(userIds[0]) - if err != nil { - log.Printf("Error in Room-Creation: %s", err) - return - } - - // Join to Room - err = joinRoom(userIds[1:]) - if err != nil { - log.Printf("Error joining Room: %s", err) - return - } - - // Send Messages with Timer -} - -func reset() (err error) { - // TODO: Implement - return -} - -func createRoom(userId string) (err error) { - accessToken := accessTokens[userId] - requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/createRoom", httpString, strings.Split(userId, ":")[1]) - request := room.CreateRoomRequest{ - Visibility: "public", - Name: "Testraum", - Topic: "Raum für die Energieeffizienz-Tests", - RoomVersion: "1", - CreationContent: room.CreationContent{ - Federated: true, - }, - Preset: "public_chat", - IsDirect: true, - } - reqBody, err := json.Marshal(request) - if err != nil { - return - } - client := &http.Client{} - req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody)) - if err != nil { - return - } - req.Header["Content-Type"] = []string{"application/json"} - req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", accessToken)} - res, err := client.Do(req) - if res.StatusCode != http.StatusOK { - handleError(res) - } else { - response := room.CreateRoomResponse{} - decoder := json.NewDecoder(res.Body) - err = decoder.Decode(&response) - if err != nil { - return - } - roomId = response.RoomId - log.Printf("Room created: %s", roomId) - } - return -} - -func joinRoom(userIdsToJoin []string) (err error) { - for _, userId := range userIdsToJoin { - err = joinRoomUser(userId) - if err != nil { - return - } - } - return -} - -func joinRoomUser(userId string) (err error) { - accessToken := accessTokens[userId] - requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/rooms/%s/join", httpString, strings.Split(userId, ":")[1], roomId) - request := room.JoinRoomUserRequest{} - reqBody, err := json.Marshal(request) - if err != nil { - return - } - client := &http.Client{} - req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody)) - if err != nil { - return - } - req.Header["Content-Type"] = []string{"application/json"} - req.Header["Authorization"] = []string{fmt.Sprintf("Bearer %s", accessToken)} - res, err := client.Do(req) - if res.StatusCode != http.StatusOK { - handleError(res) - } else { - response := room.JoinRoomUserResponse{} - decoder := json.NewDecoder(res.Body) - err = decoder.Decode(&response) - if err != nil { - return - } - roomId = response.RoomId - log.Printf("%s joined Room", userId) - } - return -} - -func createUsers() (err error) { - for _, userToCreate := range users { - var userId string - var accessToken string - userId, accessToken, err = createUser(userToCreate, "localhost") - if err != nil { - return - } - if userId != "" && accessToken != "" { - log.Printf("%s: %s", userId, accessToken) - accessTokens[userId] = accessToken - userIds = append(userIds, userId) - } - } - return -} - -func createUser(userToCreate string, homeserver string) (userId string, accessToken string, err error) { - requestUrl := fmt.Sprintf("%s://%s/_matrix/client/r0/register", httpString, homeserver) - request := user.RegisterRequest{ - Auth: user.AuthentificationData{ - LoginType: "m.login.password", - }, - Username: userToCreate, - Password: "password", - DeviceName: fmt.Sprintf("%s's device", userToCreate), - } - reqBody, err := json.Marshal(request) - if err != nil { - return - } - client := &http.Client{} - req, err := http.NewRequest(http.MethodPost, requestUrl, bytes.NewBuffer(reqBody)) - if err != nil { - return - } - req.Header["Content-Type"] = []string{"application/json"} - res, err := client.Do(req) - if res.StatusCode != http.StatusOK { - handleError(res) - } else { - response := user.RegisterResponse{} - decoder := json.NewDecoder(res.Body) - err = decoder.Decode(&response) - if err != nil { - return - } - userId = response.UserId - accessToken = response.AccessToken - } - return -} - -func handleError(res *http.Response) { - response := utils.ErrorResponse{} - decoder := json.NewDecoder(res.Body) - err := decoder.Decode(&response) - if err != nil { - log.Printf("Error not parseable") - return - } - log.Printf("%s (%s)", response.ErrorMessage, response.ErrorCode) -}