diff --git a/internal/backend.go b/internal/backend.go index fe020f0..40b7ab2 100644 --- a/internal/backend.go +++ b/internal/backend.go @@ -9,12 +9,12 @@ import ( ) type Backend interface { - Register(username, password, device string) (user User, token string, err *models.ApiError) - Login(username, password, device string) (user User, token string, err *models.ApiError) + Register(username, password, device string) (user User, token string, err models.ApiError) + Login(username, password, device string) (user User, token string, err models.ApiError) GetUserByToken(token string) (user User) GetUserByName(userName string) User GetRoomByID(id string) Room - Sync(token string, request sync.SyncRequest) (response *sync.SyncReply, err *models.ApiError) + Sync(token string, request sync.SyncRequest) (response *sync.SyncReply, err models.ApiError) PublicRooms() []Room } @@ -37,15 +37,15 @@ type User interface { Name() string ID() string Password() string - CreateRoom(request createroom.Request) (Room, *models.ApiError) - LeaveRoom(room Room) *models.ApiError - SetTopic(room Room, topic string) *models.ApiError - SendMessage(room Room, text string) *models.ApiError + CreateRoom(request createroom.Request) (Room, models.ApiError) + LeaveRoom(room Room) models.ApiError + SetTopic(room Room, topic string) models.ApiError + SendMessage(room Room, text string) models.ApiError JoinedRooms() []Room ChangePassword(newPassword string) Devices() []devices.Device - SetRoomVisibility(Room, createroom.VisibilityType) *models.ApiError + SetRoomVisibility(Room, createroom.VisibilityType) models.ApiError Logout(token string) LogoutAll() - JoinRoom(Room) *models.ApiError + JoinRoom(Room) models.ApiError } diff --git a/internal/backends/memory/backend.go b/internal/backends/memory/backend.go index d67b5e7..4c5919b 100644 --- a/internal/backends/memory/backend.go +++ b/internal/backends/memory/backend.go @@ -29,12 +29,12 @@ func NewBackend(hostname string) *Backend { data: make(map[string]internal.User)} } -func (backend *Backend) Register(username, password, device string) (user internal.User, token string, err *models.ApiError) { +func (backend *Backend) Register(username, password, device string) (user internal.User, token string, err models.ApiError) { backend.mutex.Lock() if _, ok := backend.data[username]; ok { backend.mutex.Unlock() - return nil, "", internal.NewError(models.M_USER_IN_USE, "trying to register a user ID which has been taken") + return nil, "", models.NewError(models.M_USER_IN_USE, "trying to register a user ID which has been taken") } user = &User{ @@ -49,17 +49,17 @@ func (backend *Backend) Register(username, password, device string) (user intern return backend.Login(username, password, device) } -func (backend *Backend) Login(username, password, device string) (user internal.User, token string, err *models.ApiError) { +func (backend *Backend) Login(username, password, device string) (user internal.User, token string, err models.ApiError) { backend.mutex.Lock() defer backend.mutex.Unlock() user, ok := backend.data[username] if !ok { - return nil, "", internal.NewError(models.M_FORBIDDEN, "wrong username") + return nil, "", models.NewError(models.M_FORBIDDEN, "wrong username") } if user.Password() != password { - return nil, "", internal.NewError(models.M_FORBIDDEN, "wrong password") + return nil, "", models.NewError(models.M_FORBIDDEN, "wrong password") } token = newToken(defaultTokenSize) @@ -69,7 +69,7 @@ func (backend *Backend) Login(username, password, device string) (user internal. return user, token, nil } -func (backend *Backend) Sync(token string, request mSync.SyncRequest) (response *mSync.SyncReply, err *models.ApiError) { +func (backend *Backend) Sync(token string, request mSync.SyncRequest) (response *mSync.SyncReply, err models.ApiError) { backend.mutex.Lock() defer backend.mutex.Unlock() diff --git a/internal/backends/memory/backend_test.go b/internal/backends/memory/backend_test.go index c24877c..5c0dbc8 100644 --- a/internal/backends/memory/backend_test.go +++ b/internal/backends/memory/backend_test.go @@ -18,7 +18,7 @@ func TestRegisterUser(t *testing.T) { ) user, token, err := backend.Register(username, password, device) - assert.Nil(t, err) + assert.NoError(t, err) assert.Equal(t, username, user.Name()) assert.Equal(t, password, user.Password()) assert.NotEmpty(t, token) @@ -32,7 +32,7 @@ func TestRegisterUserWithAlreadyTakenName(t *testing.T) { ) _, _, err := backend.Register(userName, "", "") - assert.Nil(t, err) + assert.NoError(t, err) _, _, err = backend.Register(userName, "", "") assert.NotNil(t, err) @@ -47,10 +47,10 @@ func TestLogin(t *testing.T) { ) _, _, err := backend.Register(userName, password, "") - assert.Nil(t, err) + assert.NoError(t, err) _, token, err := backend.Login(userName, password, "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotZero(t, token) } @@ -63,7 +63,7 @@ func TestLoginWithWrongCredentials(t *testing.T) { ) _, _, err := backend.Register(userName, password, "") - assert.Nil(t, err) + assert.NoError(t, err) _, _, err = backend.Login(userName, "wrong password", "") assert.NotNil(t, err) @@ -81,10 +81,10 @@ func TestLogout(t *testing.T) { ) user, _, err := backend.Register(userName, password, "") - assert.Nil(t, err) + assert.NoError(t, err) _, token, err := backend.Login(userName, password, "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotZero(t, token) user.Logout(token) @@ -96,7 +96,7 @@ func TestGetRoomByID(t *testing.T) { backend := NewBackend("localhost") user, token, err := backend.Register("user", "", "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotNil(t, user) assert.NotEmpty(t, token) @@ -105,7 +105,7 @@ func TestGetRoomByID(t *testing.T) { Name: "room1"} room, err := user.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) assert.NotNil(t, room) assert.Equal(t, room.ID(), backend.GetRoomByID(room.ID()).ID()) @@ -122,7 +122,7 @@ func TestGetUserByName(t *testing.T) { ) user, token, err := backend.Register(userName, "", "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotNil(t, user) assert.NotEmpty(t, token) @@ -141,7 +141,7 @@ func TestPublicRooms(t *testing.T) { backend := NewBackend("localhost") user1, _, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotNil(t, user1) // Create first room @@ -151,7 +151,7 @@ func TestPublicRooms(t *testing.T) { Preset: createroom.PublicChat} room1, err := user1.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) assert.NotNil(t, room1) // Create second room @@ -161,16 +161,16 @@ func TestPublicRooms(t *testing.T) { Preset: createroom.PublicChat} room2, err := user1.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) assert.NotNil(t, room2) // Make room2 has 2 users user2, _, err := backend.Register("user2", "", "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotNil(t, user2) err = user2.JoinRoom(room2) - assert.Nil(t, err) + assert.NoError(t, err) rooms := backend.PublicRooms() assert.Len(t, rooms, 2) diff --git a/internal/backends/memory/rooms_test.go b/internal/backends/memory/rooms_test.go index d71529f..4ca4103 100644 --- a/internal/backends/memory/rooms_test.go +++ b/internal/backends/memory/rooms_test.go @@ -12,7 +12,7 @@ func TestCreateRoom(t *testing.T) { backend := NewBackend("localhost") user, _, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) request := createroom.Request{ RoomAliasName: "room1", @@ -20,7 +20,7 @@ func TestCreateRoom(t *testing.T) { Topic: "topic"} room, err := user.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) assert.Equal(t, request.RoomAliasName, room.AliasName()) assert.Equal(t, request.Name, room.Name()) assert.Equal(t, request.Topic, room.Topic()) @@ -40,7 +40,7 @@ func TestCreateAlreadyExistingRoom(t *testing.T) { Topic: "topic"} _, err := user.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) _, err = user.CreateRoom(request) assert.NotNil(t, err) @@ -60,7 +60,7 @@ func TestSetRoomTopic(t *testing.T) { var newTopic = "new topic" err := user.SetTopic(room, newTopic) - assert.Nil(t, err) + assert.NoError(t, err) assert.Equal(t, newTopic, room.Topic()) assert.Equal(t, 5, len(room.Events())) // TODO: check start event count } @@ -109,7 +109,7 @@ func TestRoomUserCount(t *testing.T) { backend := NewBackend("localhost") user1, _, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) request := createroom.Request{ RoomAliasName: "room1", @@ -117,7 +117,7 @@ func TestRoomUserCount(t *testing.T) { Topic: "topic"} room, err := user1.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) assert.Len(t, room.Users(), 1) // TODO: add join another user test diff --git a/internal/backends/memory/user.go b/internal/backends/memory/user.go index 221e0ad..49f5b85 100644 --- a/internal/backends/memory/user.go +++ b/internal/backends/memory/user.go @@ -33,10 +33,10 @@ func (user *User) Password() string { return user.password } -func (user *User) CreateRoom(request createroom.Request) (internal.Room, *models.ApiError) { +func (user *User) CreateRoom(request createroom.Request) (internal.Room, models.ApiError) { for _, existingRoom := range user.backend.rooms { if existingRoom.AliasName() == request.RoomAliasName { // TODO: strip and check request room alias name before use - return nil, internal.NewError(models.M_ROOM_IN_USE, "") + return nil, models.NewError(models.M_ROOM_IN_USE, "") } } @@ -104,12 +104,12 @@ func (user *User) CreateRoom(request createroom.Request) (internal.Room, *models return room, nil } -func (user *User) SetTopic(room internal.Room, topic string) *models.ApiError { +func (user *User) SetTopic(room internal.Room, topic string) models.ApiError { room.(*Room).mutex.Lock() defer room.(*Room).mutex.Unlock() if room.(*Room).creator.ID() != user.ID() { // TODO: currently only creator can change topic - return internal.NewError(models.M_FORBIDDEN, "") + return models.NewError(models.M_FORBIDDEN, "") } room.(*Room).topic = topic @@ -122,7 +122,7 @@ func (user *User) SetTopic(room internal.Room, topic string) *models.ApiError { return nil } -func (user *User) LeaveRoom(room internal.Room) *models.ApiError { +func (user *User) LeaveRoom(room internal.Room) models.ApiError { room.(*Room).mutex.Lock() defer room.(*Room).mutex.Unlock() @@ -133,10 +133,10 @@ func (user *User) LeaveRoom(room internal.Room) *models.ApiError { } } - return internal.NewError(models.M_BAD_STATE, "you are not a member of group") // TODO: check error code + return models.NewError(models.M_BAD_STATE, "you are not a member of group") // TODO: check error code } -func (user *User) SendMessage(room internal.Room, text string) *models.ApiError { +func (user *User) SendMessage(room internal.Room, text string) models.ApiError { room.(*Room).mutex.Lock() defer room.(*Room).mutex.Unlock() @@ -148,7 +148,7 @@ func (user *User) SendMessage(room internal.Room, text string) *models.ApiError } if !userInRoom { - return internal.NewError(models.M_FORBIDDEN, "") + return models.NewError(models.M_FORBIDDEN, "") } room.(*Room).events = append(room.(*Room).events, RoomEvent{ @@ -195,9 +195,9 @@ func (user *User) Devices() []devices.Device { return result } -func (user *User) SetRoomVisibility(room internal.Room, visibilityType createroom.VisibilityType) *models.ApiError { +func (user *User) SetRoomVisibility(room internal.Room, visibilityType createroom.VisibilityType) models.ApiError { if user.ID() != room.Creator().ID() { - return internal.NewError(models.M_FORBIDDEN, "only room owner can change visibility") // TODO: room administrators can use this method too + return models.NewError(models.M_FORBIDDEN, "only room owner can change visibility") // TODO: room administrators can use this method too } room.(*Room).mutex.Lock() @@ -223,7 +223,7 @@ func (user *User) LogoutAll() { user.Tokens = make(map[string]Token) } -func (user *User) JoinRoom(room internal.Room) *models.ApiError { +func (user *User) JoinRoom(room internal.Room) models.ApiError { memRoom := room.(*Room) memRoom.mutex.Lock() @@ -231,7 +231,7 @@ func (user *User) JoinRoom(room internal.Room) *models.ApiError { for _, roomUser := range memRoom.joined { if roomUser.ID() == user.ID() { - return internal.NewError(models.M_BAD_STATE, "user already in room") // TODO: check code + return models.NewError(models.M_BAD_STATE, "user already in room") // TODO: check code } } diff --git a/internal/backends/memory/user_test.go b/internal/backends/memory/user_test.go index 53e93cf..1cc06cc 100644 --- a/internal/backends/memory/user_test.go +++ b/internal/backends/memory/user_test.go @@ -19,7 +19,7 @@ func TestUserID(t *testing.T) { backend := NewBackend(hostName) user, _, err := backend.Register(userName, "", "") - assert.Nil(t, err) + assert.NoError(t, err) assert.Equal(t, expectedUserID, user.ID()) } @@ -28,34 +28,34 @@ func TestUserMessage(t *testing.T) { backend := NewBackend("localhost") user, _, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) request := createroom.Request{ RoomAliasName: "room1", Name: "room1"} room, err := user.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) err = user.SendMessage(room, "hello") - assert.Nil(t, err) + assert.NoError(t, err) } func TestUserMessageInWrongRoom(t *testing.T) { backend := NewBackend("localhost") user1, _, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) request := createroom.Request{ RoomAliasName: "room1", Name: "room1"} room, err := user1.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) user2, _, err := backend.Register("user2", "", "") - assert.Nil(t, err) + assert.NoError(t, err) err = user2.SendMessage(room, "hello") assert.NotNil(t, err) @@ -65,7 +65,7 @@ func TestGetUserByToken(t *testing.T) { backend := NewBackend("localhost") user, token, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotEmpty(t, token) gotUser := backend.GetUserByToken(token) @@ -76,7 +76,7 @@ func TestGetUserByWrongToken(t *testing.T) { backend := NewBackend("localhost") _, token, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotEmpty(t, token) gotUser := backend.GetUserByToken("wrong token") @@ -92,10 +92,10 @@ func TestLogoutWithWrongToken(t *testing.T) { ) user, _, err := backend.Register(userName, password, "") - assert.Nil(t, err) + assert.NoError(t, err) _, token, err := backend.Login(userName, password, "") - assert.Nil(t, err) + assert.NoError(t, err) assert.NotZero(t, token) user.Logout("worng token") @@ -105,7 +105,7 @@ func TestJoinedRooms(t *testing.T) { backend := NewBackend("localhost") user, _, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) request := createroom.Request{ RoomAliasName: "room1", @@ -113,7 +113,7 @@ func TestJoinedRooms(t *testing.T) { Topic: "topic"} room, err := user.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) rooms := user.JoinedRooms() assert.Equal(t, []internal.Room{room}, rooms) @@ -125,7 +125,7 @@ func TestNewPassword(t *testing.T) { var newPassword = "new password" user, _, err := backend.Register("user1", "old password", "") - assert.Nil(t, err) + assert.NoError(t, err) user.ChangePassword(newPassword) assert.Equal(t, newPassword, user.Password()) @@ -137,7 +137,7 @@ func TestDevices(t *testing.T) { var expectedDeviceID = "my device" user, _, err := backend.Register("user1", "", expectedDeviceID) - assert.Nil(t, err) + assert.NoError(t, err) devices := user.Devices() assert.Len(t, devices, 1) @@ -148,7 +148,7 @@ func TestSetRoomVisibility(t *testing.T) { backend := NewBackend("localhost") user, _, err := backend.Register("user1", "", "") - assert.Nil(t, err) + assert.NoError(t, err) request := createroom.Request{ RoomAliasName: "room1", @@ -156,17 +156,17 @@ func TestSetRoomVisibility(t *testing.T) { Visibility: createroom.VisibilityTypePrivate} room, err := user.CreateRoom(request) - assert.Nil(t, err) + assert.NoError(t, err) assert.NotNil(t, room) assert.Equal(t, createroom.VisibilityTypePrivate, room.Visibility()) err = user.SetRoomVisibility(room, createroom.VisibilityTypePublic) - assert.Nil(t, err) + assert.NoError(t, err) assert.Equal(t, createroom.VisibilityTypePublic, room.Visibility()) // TODO: Only owner can change room visibility notOwnerUser, _, err := backend.Register("user2", "", "") - assert.Nil(t, err) + assert.NoError(t, err) err = notOwnerUser.SetRoomVisibility(room, createroom.VisibilityTypePrivate) assert.NotNil(t, err) @@ -182,11 +182,11 @@ func TestLogoutAll(t *testing.T) { ) user, _, err := backend.Register(userName, password, "dev1") - assert.Nil(t, err) + assert.NoError(t, err) assert.Len(t, user.Devices(), 1) _, _, err = backend.Login(userName, password, "dev2") - assert.Nil(t, err) + assert.NoError(t, err) assert.Len(t, user.Devices(), 2) user.LogoutAll() diff --git a/internal/errors.go b/internal/errors.go index 0bfcf75..99c6ece 100644 --- a/internal/errors.go +++ b/internal/errors.go @@ -6,21 +6,14 @@ import ( "github.com/nxshock/signaller/internal/models" ) -func errorResponse(w http.ResponseWriter, code models.ApiError, httpCode int, message string) { +func errorResponse(w http.ResponseWriter, code models.ApiError, httpCode int, messageOverride string) { w.Header().Set("Content-Type", "application/json") - if message != "" { - code.Message = message - } - w.WriteHeader(httpCode) - w.Write(code.JSON()) -} -func NewError(code models.ApiError, message string) *models.ApiError { - if message != "" { - code.Message = message + if messageOverride != "" { + w.Write(models.NewError(code, messageOverride).JSON()) + } else { + w.Write(code.JSON()) } - - return &code } diff --git a/internal/handlers.go b/internal/handlers.go index 4ba8c58..f458c95 100644 --- a/internal/handlers.go +++ b/internal/handlers.go @@ -68,7 +68,7 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) { _, token, apiErr := currServer.Backend.Login(request.Identifier.User, request.Password, request.DeviceID) if apiErr != nil { - errorResponse(w, *apiErr, http.StatusForbidden, "") + errorResponse(w, apiErr, http.StatusForbidden, "") return } @@ -110,7 +110,7 @@ func leaveRoomHandler(w http.ResponseWriter, r *http.Request) { err := user.LeaveRoom(room) if err != nil { - errorResponse(w, *err, http.StatusBadRequest, "") + errorResponse(w, err, http.StatusBadRequest, "") return } @@ -185,7 +185,7 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) { _, token, apiErr := currServer.Backend.Register(request.Username, request.Password, request.DeviceID) if apiErr != nil { - errorResponse(w, *apiErr, http.StatusBadRequest, "") + errorResponse(w, apiErr, http.StatusBadRequest, "") return } diff --git a/internal/models/errors.go b/internal/models/errors.go index 3f8f614..e14ee70 100644 --- a/internal/models/errors.go +++ b/internal/models/errors.go @@ -4,49 +4,86 @@ import ( "encoding/json" ) -type ApiError struct { - Code string `json:"errcode"` - Message string `json:"error"` +type ApiError interface { + error + Code() string + Message() string + JSON() []byte +} + +type apiError struct { + code string `json:"errcode"` + message string `json:"error"` +} + +func (apiError *apiError) Error() string { + s := apiError.code + + if apiError.message != "" { + s = s + ": " + apiError.message + } + + return s +} + +func (apiError *apiError) Code() string { + return apiError.code +} + +func (apiError *apiError) Message() string { + return apiError.message +} + +func (apiError *apiError) JSON() []byte { + b, _ := json.Marshal(apiError) // TODO: error handler? + return b } var ( // https://matrix.org/docs/spec/client_server/latest#api-standards - M_FORBIDDEN = ApiError{"M_FORBIDDEN", ""} // Forbidden access, e.g. joining a room without permission, failed login. - M_UNKNOWN_TOKEN = ApiError{"M_UNKNOWN_TOKEN", ""} // The access token specified was not recognised. - M_MISSING_TOKEN = ApiError{"M_MISSING_TOKEN", ""} // No access token was specified for the request. - M_BAD_JSON = ApiError{"M_BAD_JSON", ""} // Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. - M_NOT_JSON = ApiError{"M_NOT_JSON", ""} // Request did not contain valid JSON. - M_NOT_FOUND = ApiError{"M_NOT_FOUND", ""} // No resource was found for this request. - M_LIMIT_EXCEEDED = ApiError{"M_LIMIT_EXCEEDED", ""} // Too many requests have been sent in a short period of time. Wait a while then try again. - M_UNKNOWN = ApiError{"M_UNKNOWN", ""} // An unknown error has occurred. + M_FORBIDDEN = &apiError{"M_FORBIDDEN", ""} // Forbidden access, e.g. joining a room without permission, failed login. + M_UNKNOWN_TOKEN = &apiError{"M_UNKNOWN_TOKEN", ""} // The access token specified was not recognised. + M_MISSING_TOKEN = &apiError{"M_MISSING_TOKEN", ""} // No access token was specified for the request. + M_BAD_JSON = &apiError{"M_BAD_JSON", ""} // Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. + M_NOT_JSON = &apiError{"M_NOT_JSON", ""} // Request did not contain valid JSON. + M_NOT_FOUND = &apiError{"M_NOT_FOUND", ""} // No resource was found for this request. + M_LIMIT_EXCEEDED = &apiError{"M_LIMIT_EXCEEDED", ""} // Too many requests have been sent in a short period of time. Wait a while then try again. + M_UNKNOWN = &apiError{"M_UNKNOWN", ""} // An unknown error has occurred. - M_UNRECOGNIZED = ApiError{"M_UNRECOGNIZED", ""} // The server did not understand the request. - M_UNAUTHORIZED = ApiError{"M_UNAUTHORIZED", ""} // The request was not correctly authorized. Usually due to login failures. - M_USER_IN_USE = ApiError{"M_USER_IN_USE", ""} // Encountered when trying to register a user ID which has been taken. - M_INVALID_USERNAME = ApiError{"M_INVALID_USERNAME", ""} // Encountered when trying to register a user ID which is not valid. - M_ROOM_IN_USE = ApiError{"M_ROOM_IN_USE", ""} // Sent when the room alias given to the createRoom API is already in use. - M_INVALID_ROOM_STATE = ApiError{"M_INVALID_ROOM_STATE", ""} // Sent when the initial state given to the createRoom API is invalid. - M_THREEPID_IN_USE = ApiError{"M_THREEPID_IN_USE", ""} // Sent when a threepid given to an API cannot be used because the same threepid is already in use. - M_THREEPID_NOT_FOUND = ApiError{"M_THREEPID_NOT_FOUND", ""} // Sent when a threepid given to an API cannot be used because no record matching the threepid was found. - M_THREEPID_AUTH_FAILED = ApiError{"M_THREEPID_AUTH_FAILED", ""} // Authentication could not be performed on the third party identifier. - M_THREEPID_DENIED = ApiError{"M_THREEPID_DENIED", ""} // The server does not permit this third party identifier. This may happen if the server only permits, for example, email addresses from a particular domain. - M_SERVER_NOT_TRUSTED = ApiError{"M_SERVER_NOT_TRUSTED", ""} // The client's request used a third party server, eg. identity server, that this server does not trust. - M_UNSUPPORTED_ROOM_VERSION = ApiError{"M_UNSUPPORTED_ROOM_VERSION", ""} // The client's request to create a room used a room version that the server does not support. - M_INCOMPATIBLE_ROOM_VERSION = ApiError{"M_INCOMPATIBLE_ROOM_VERSION", ""} // The client attempted to join a room that has a version the server does not support. Inspect the room_version property of the error response for the room's version. - M_BAD_STATE = ApiError{"M_BAD_STATE", ""} // The state change requested cannot be performed, such as attempting to unban a user who is not banned. - M_GUEST_ACCESS_FORBIDDEN = ApiError{"M_GUEST_ACCESS_FORBIDDEN", ""} // The room or resource does not permit guests to access it. - M_CAPTCHA_NEEDED = ApiError{"M_CAPTCHA_NEEDED", ""} // A Captcha is required to complete the request. - M_CAPTCHA_INVALID = ApiError{"M_CAPTCHA_INVALID", ""} // The Captcha provided did not match what was expected. - M_MISSING_PARAM = ApiError{"M_MISSING_PARAM", ""} // A required parameter was missing from the request. - M_INVALID_PARAM = ApiError{"M_INVALID_PARAM", ""} // A parameter that was specified has the wrong value. For example, the server expected an integer and instead received a string. - M_TOO_LARGE = ApiError{"M_TOO_LARGE", ""} // The request or entity was too large. - M_EXCLUSIVE = ApiError{"M_EXCLUSIVE", ""} // The resource being requested is reserved by an application service, or the application service making the request has not created the resource. - M_RESOURCE_LIMIT_EXCEEDED = ApiError{"M_RESOURCE_LIMIT_EXCEEDED", ""} // The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example, a homeserver held in a shared hosting environment may reach a resource limit if it starts using too much memory or disk space. The error MUST have an admin_contact field to provide the user receiving the error a place to reach out to. Typically, this error will appear on routes which attempt to modify state (eg: sending messages, account data, etc) and not routes which only read state (eg: /sync, get account data, etc). - M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = ApiError{"M_CANNOT_LEAVE_SERVER_NOTICE_ROOM", ""} // The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information. + M_UNRECOGNIZED = &apiError{"M_UNRECOGNIZED", ""} // The server did not understand the request. + M_UNAUTHORIZED = &apiError{"M_UNAUTHORIZED", ""} // The request was not correctly authorized. Usually due to login failures. + M_USER_IN_USE = &apiError{"M_USER_IN_USE", ""} // Encountered when trying to register a user ID which has been taken. + M_INVALID_USERNAME = &apiError{"M_INVALID_USERNAME", ""} // Encountered when trying to register a user ID which is not valid. + M_ROOM_IN_USE = &apiError{"M_ROOM_IN_USE", ""} // Sent when the room alias given to the createRoom API is already in use. + M_INVALID_ROOM_STATE = &apiError{"M_INVALID_ROOM_STATE", ""} // Sent when the initial state given to the createRoom API is invalid. + M_THREEPID_IN_USE = &apiError{"M_THREEPID_IN_USE", ""} // Sent when a threepid given to an API cannot be used because the same threepid is already in use. + M_THREEPID_NOT_FOUND = &apiError{"M_THREEPID_NOT_FOUND", ""} // Sent when a threepid given to an API cannot be used because no record matching the threepid was found. + M_THREEPID_AUTH_FAILED = &apiError{"M_THREEPID_AUTH_FAILED", ""} // Authentication could not be performed on the third party identifier. + M_THREEPID_DENIED = &apiError{"M_THREEPID_DENIED", ""} // The server does not permit this third party identifier. This may happen if the server only permits, for example, email addresses from a particular domain. + M_SERVER_NOT_TRUSTED = &apiError{"M_SERVER_NOT_TRUSTED", ""} // The client's request used a third party server, eg. identity server, that this server does not trust. + M_UNSUPPORTED_ROOM_VERSION = &apiError{"M_UNSUPPORTED_ROOM_VERSION", ""} // The client's request to create a room used a room version that the server does not support. + M_INCOMPATIBLE_ROOM_VERSION = &apiError{"M_INCOMPATIBLE_ROOM_VERSION", ""} // The client attempted to join a room that has a version the server does not support. Inspect the room_version property of the error response for the room's version. + M_BAD_STATE = &apiError{"M_BAD_STATE", ""} // The state change requested cannot be performed, such as attempting to unban a user who is not banned. + M_GUEST_ACCESS_FORBIDDEN = &apiError{"M_GUEST_ACCESS_FORBIDDEN", ""} // The room or resource does not permit guests to access it. + M_CAPTCHA_NEEDED = &apiError{"M_CAPTCHA_NEEDED", ""} // A Captcha is required to complete the request. + M_CAPTCHA_INVALID = &apiError{"M_CAPTCHA_INVALID", ""} // The Captcha provided did not match what was expected. + M_MISSING_PARAM = &apiError{"M_MISSING_PARAM", ""} // A required parameter was missing from the request. + M_INVALID_PARAM = &apiError{"M_INVALID_PARAM", ""} // A parameter that was specified has the wrong value. For example, the server expected an integer and instead received a string. + M_TOO_LARGE = &apiError{"M_TOO_LARGE", ""} // The request or entity was too large. + M_EXCLUSIVE = &apiError{"M_EXCLUSIVE", ""} // The resource being requested is reserved by an application service, or the application service making the request has not created the resource. + M_RESOURCE_LIMIT_EXCEEDED = &apiError{"M_RESOURCE_LIMIT_EXCEEDED", ""} // The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example, a homeserver held in a shared hosting environment may reach a resource limit if it starts using too much memory or disk space. The error MUST have an admin_contact field to provide the user receiving the error a place to reach out to. Typically, this error will appear on routes which attempt to modify state (eg: sending messages, account data, etc) and not routes which only read state (eg: /sync, get account data, etc). + M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = &apiError{"M_CANNOT_LEAVE_SERVER_NOTICE_ROOM", ""} // The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information. ) -func (apiError ApiError) JSON() []byte { - b, _ := json.Marshal(apiError) // TODO: error handler? - return b +func NewError(err ApiError, messageOverride string) ApiError { + newErr := &apiError{ + code: err.Code(), + message: err.Message()} + + if messageOverride != "" { + newErr.message = messageOverride + } + + return newErr }