2019-07-21 09:43:14 +00:00
|
|
|
package memory
|
|
|
|
|
2019-07-21 11:52:32 +00:00
|
|
|
import (
|
2019-08-06 15:28:39 +00:00
|
|
|
"fmt"
|
2019-07-25 16:56:31 +00:00
|
|
|
"sync"
|
2019-07-21 11:52:32 +00:00
|
|
|
"time"
|
|
|
|
|
2019-08-03 14:19:18 +00:00
|
|
|
"github.com/signaller-matrix/signaller/internal"
|
|
|
|
"github.com/signaller-matrix/signaller/internal/models"
|
2019-08-05 15:06:46 +00:00
|
|
|
"github.com/signaller-matrix/signaller/internal/models/common"
|
2019-08-03 14:19:18 +00:00
|
|
|
"github.com/signaller-matrix/signaller/internal/models/createroom"
|
|
|
|
"github.com/signaller-matrix/signaller/internal/models/devices"
|
|
|
|
"github.com/signaller-matrix/signaller/internal/models/rooms"
|
2019-07-21 11:52:32 +00:00
|
|
|
)
|
|
|
|
|
2019-07-21 09:43:14 +00:00
|
|
|
type User struct {
|
|
|
|
name string
|
|
|
|
password string
|
|
|
|
Tokens map[string]Token
|
2019-08-05 15:06:46 +00:00
|
|
|
filters map[string]common.Filter
|
2019-07-21 09:43:14 +00:00
|
|
|
|
|
|
|
backend *Backend
|
2019-07-25 16:56:31 +00:00
|
|
|
|
|
|
|
mutex sync.RWMutex
|
2019-07-21 09:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (user *User) ID() string {
|
2019-07-21 11:04:02 +00:00
|
|
|
return "@" + user.name + ":" + user.backend.hostname
|
2019-07-21 09:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (user *User) Name() string {
|
|
|
|
return user.name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (user *User) Password() string {
|
|
|
|
return user.password
|
|
|
|
}
|
2019-07-21 11:52:32 +00:00
|
|
|
|
2019-08-03 06:46:57 +00:00
|
|
|
func (user *User) CreateRoom(request createroom.Request) (internal.Room, models.ApiError) {
|
2019-07-21 11:52:32 +00:00
|
|
|
for _, existingRoom := range user.backend.rooms {
|
|
|
|
if existingRoom.AliasName() == request.RoomAliasName { // TODO: strip and check request room alias name before use
|
2019-08-03 06:46:57 +00:00
|
|
|
return nil, models.NewError(models.M_ROOM_IN_USE, "")
|
2019-07-21 11:52:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-21 12:08:16 +00:00
|
|
|
t := time.Now()
|
|
|
|
|
|
|
|
events := make([]RoomEvent, 0)
|
|
|
|
|
|
|
|
// Create room event
|
|
|
|
events = append(events, RoomEvent{
|
|
|
|
Content: nil,
|
|
|
|
Type: rooms.Create,
|
2019-08-04 16:46:31 +00:00
|
|
|
EventID: internal.RandomString(eventIDSize),
|
2019-07-21 12:08:16 +00:00
|
|
|
Sender: user,
|
|
|
|
OriginServerTS: t})
|
|
|
|
|
2019-07-22 13:46:59 +00:00
|
|
|
// TODO: Add join room event
|
|
|
|
|
2019-07-21 12:08:16 +00:00
|
|
|
// Set join rules event
|
|
|
|
events = append(events, RoomEvent{
|
|
|
|
Content: []byte(request.Visibility), // TODO: check visibility vs join rules
|
|
|
|
Type: rooms.JoinRules,
|
2019-08-04 16:46:31 +00:00
|
|
|
EventID: internal.RandomString(eventIDSize),
|
2019-07-21 12:08:16 +00:00
|
|
|
Sender: user,
|
|
|
|
OriginServerTS: t})
|
|
|
|
|
|
|
|
// Set room name event
|
|
|
|
if request.Name != "" {
|
|
|
|
events = append(events, RoomEvent{
|
|
|
|
Content: nil, // TODO: add
|
|
|
|
Type: rooms.Name,
|
2019-08-04 16:46:31 +00:00
|
|
|
EventID: internal.RandomString(eventIDSize),
|
2019-07-21 12:08:16 +00:00
|
|
|
Sender: user,
|
|
|
|
OriginServerTS: t})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set room alias event
|
|
|
|
if request.RoomAliasName != "" {
|
|
|
|
events = append(events, RoomEvent{
|
|
|
|
Content: nil, // TODO: add
|
|
|
|
Type: rooms.CanonicalAlias,
|
2019-08-04 16:46:31 +00:00
|
|
|
EventID: internal.RandomString(eventIDSize),
|
2019-07-21 12:08:16 +00:00
|
|
|
Sender: user,
|
|
|
|
OriginServerTS: t})
|
|
|
|
}
|
|
|
|
|
2019-07-21 11:52:32 +00:00
|
|
|
room := &Room{
|
2019-08-04 16:46:31 +00:00
|
|
|
id: internal.RandomString(groupIDSize),
|
2019-07-31 15:01:20 +00:00
|
|
|
aliasName: request.RoomAliasName,
|
|
|
|
name: request.Name,
|
|
|
|
topic: request.Topic,
|
|
|
|
creator: user,
|
|
|
|
joined: []internal.User{user},
|
|
|
|
visibility: request.Visibility,
|
2019-08-02 16:48:48 +00:00
|
|
|
server: user.backend,
|
|
|
|
state: request.Preset}
|
2019-07-21 12:08:16 +00:00
|
|
|
|
2019-08-07 09:07:11 +00:00
|
|
|
for i, _ := range events {
|
|
|
|
events[i].Room = room
|
2019-07-21 12:08:16 +00:00
|
|
|
//v.Room = room
|
|
|
|
}
|
2019-07-21 11:52:32 +00:00
|
|
|
|
2019-08-07 09:07:11 +00:00
|
|
|
for i, _ := range events {
|
|
|
|
user.backend.PutEvent(events[i].ToEvent())
|
|
|
|
}
|
|
|
|
|
2019-07-31 15:01:20 +00:00
|
|
|
user.backend.rooms[room.ID()] = room
|
2019-07-21 11:52:32 +00:00
|
|
|
|
|
|
|
return room, nil
|
|
|
|
}
|
2019-07-22 13:38:02 +00:00
|
|
|
|
2019-08-03 06:46:57 +00:00
|
|
|
func (user *User) SetTopic(room internal.Room, topic string) models.ApiError {
|
2019-08-08 15:01:55 +00:00
|
|
|
memRoom := room.(*Room)
|
2019-07-22 13:38:02 +00:00
|
|
|
|
2019-08-08 15:01:55 +00:00
|
|
|
memRoom.mutex.Lock()
|
|
|
|
defer memRoom.mutex.Unlock()
|
|
|
|
|
|
|
|
if memRoom.creator.ID() != user.ID() { // TODO: currently only creator can change topic
|
2019-08-03 06:46:57 +00:00
|
|
|
return models.NewError(models.M_FORBIDDEN, "")
|
2019-07-22 13:38:02 +00:00
|
|
|
}
|
|
|
|
|
2019-08-08 15:01:55 +00:00
|
|
|
memRoom.topic = topic
|
2019-08-07 09:07:11 +00:00
|
|
|
|
|
|
|
rEvent := &RoomEvent{
|
2019-07-22 13:38:02 +00:00
|
|
|
Type: rooms.Topic,
|
|
|
|
Sender: user,
|
|
|
|
OriginServerTS: time.Now(),
|
2019-08-07 09:07:11 +00:00
|
|
|
Room: room}
|
|
|
|
|
|
|
|
user.backend.PutEvent(rEvent.ToEvent())
|
2019-07-22 13:38:02 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2019-07-22 13:58:18 +00:00
|
|
|
|
2019-08-04 08:47:58 +00:00
|
|
|
func (user *User) Invite(room internal.Room, invitee internal.User) models.ApiError {
|
|
|
|
memRoom := room.(*Room)
|
|
|
|
|
|
|
|
memRoom.mutex.Lock()
|
|
|
|
defer memRoom.mutex.Unlock()
|
|
|
|
|
|
|
|
userInRoom := false
|
|
|
|
|
|
|
|
for _, roomUser := range memRoom.joined {
|
|
|
|
if user.ID() == roomUser.ID() {
|
|
|
|
userInRoom = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !userInRoom {
|
|
|
|
return models.NewError(models.M_FORBIDDEN, "the inviter is not currently in the room") // TODO: check code
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: remove repeated cycle
|
|
|
|
for _, roomUser := range memRoom.joined {
|
|
|
|
if roomUser.ID() == invitee.ID() {
|
|
|
|
return models.NewError(models.M_FORBIDDEN, "the invitee is already a member of the room.") // TODO: check code
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, inviteeUser := range memRoom.invites {
|
|
|
|
if inviteeUser.ID() == invitee.ID() {
|
|
|
|
return models.NewError(models.M_FORBIDDEN, "user already has been invited") // TODO: check code
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memRoom.invites = append(memRoom.invites, invitee) // TODO: add invite event + info about inviter
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-08-03 06:46:57 +00:00
|
|
|
func (user *User) LeaveRoom(room internal.Room) models.ApiError {
|
2019-08-08 15:01:55 +00:00
|
|
|
memRoom := room.(*Room)
|
|
|
|
|
|
|
|
memRoom.mutex.Lock()
|
|
|
|
defer memRoom.mutex.Unlock()
|
2019-07-22 13:58:18 +00:00
|
|
|
|
|
|
|
for i, roomMember := range room.(*Room).joined {
|
|
|
|
if roomMember.ID() == user.ID() {
|
2019-07-22 14:27:23 +00:00
|
|
|
room.(*Room).joined = append(room.(*Room).joined[:i], room.(*Room).joined[i+1:]...) // TODO: add event
|
2019-07-22 13:58:18 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-03 06:46:57 +00:00
|
|
|
return models.NewError(models.M_BAD_STATE, "you are not a member of group") // TODO: check error code
|
2019-07-22 13:58:18 +00:00
|
|
|
}
|
2019-07-23 14:24:18 +00:00
|
|
|
|
2019-08-03 06:46:57 +00:00
|
|
|
func (user *User) SendMessage(room internal.Room, text string) models.ApiError {
|
2019-08-08 15:01:55 +00:00
|
|
|
memRoom := room.(*Room)
|
|
|
|
|
|
|
|
memRoom.mutex.Lock()
|
|
|
|
defer memRoom.mutex.Unlock()
|
2019-07-23 14:24:18 +00:00
|
|
|
|
|
|
|
userInRoom := false
|
2019-08-08 15:01:55 +00:00
|
|
|
for _, roomMember := range memRoom.joined {
|
2019-07-23 14:24:18 +00:00
|
|
|
if roomMember.ID() == user.ID() {
|
|
|
|
userInRoom = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !userInRoom {
|
2019-08-03 06:46:57 +00:00
|
|
|
return models.NewError(models.M_FORBIDDEN, "")
|
2019-07-23 14:24:18 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 09:07:11 +00:00
|
|
|
rEvent := &RoomEvent{
|
2019-07-23 14:24:18 +00:00
|
|
|
Content: nil,
|
|
|
|
Type: rooms.Message,
|
2019-08-04 16:46:31 +00:00
|
|
|
EventID: internal.RandomString(defaultTokenSize),
|
2019-07-23 14:24:18 +00:00
|
|
|
Sender: user,
|
|
|
|
OriginServerTS: time.Now(),
|
2019-08-07 09:07:11 +00:00
|
|
|
Room: room}
|
|
|
|
|
|
|
|
user.backend.PutEvent(rEvent.ToEvent())
|
2019-07-23 14:24:18 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2019-07-24 14:15:07 +00:00
|
|
|
|
2019-07-24 15:04:45 +00:00
|
|
|
func (user *User) JoinedRooms() []internal.Room {
|
|
|
|
user.backend.mutex.Lock()
|
|
|
|
defer user.backend.mutex.Unlock()
|
|
|
|
|
|
|
|
var result []internal.Room
|
|
|
|
|
|
|
|
for _, room := range user.backend.rooms {
|
|
|
|
for _, user := range room.(*Room).joined {
|
|
|
|
if user.ID() == user.ID() {
|
|
|
|
result = append(result, room)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2019-07-29 14:32:38 +00:00
|
|
|
func (user *User) Devices() []devices.Device {
|
|
|
|
user.backend.mutex.Lock()
|
|
|
|
defer user.backend.mutex.Unlock()
|
|
|
|
|
|
|
|
var result []devices.Device
|
|
|
|
|
|
|
|
for _, token := range user.Tokens {
|
|
|
|
device := devices.Device{
|
|
|
|
DeviceID: token.Device}
|
|
|
|
|
|
|
|
result = append(result, device)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2019-08-03 06:46:57 +00:00
|
|
|
func (user *User) SetRoomVisibility(room internal.Room, visibilityType createroom.VisibilityType) models.ApiError {
|
2019-07-31 15:01:20 +00:00
|
|
|
if user.ID() != room.Creator().ID() {
|
2019-08-03 06:46:57 +00:00
|
|
|
return models.NewError(models.M_FORBIDDEN, "only room owner can change visibility") // TODO: room administrators can use this method too
|
2019-07-31 15:01:20 +00:00
|
|
|
}
|
|
|
|
|
2019-08-08 15:01:55 +00:00
|
|
|
memRoom := room.(*Room)
|
2019-07-31 15:01:20 +00:00
|
|
|
|
2019-08-08 15:01:55 +00:00
|
|
|
memRoom.mutex.Lock()
|
|
|
|
defer memRoom.mutex.Unlock()
|
|
|
|
|
|
|
|
memRoom.visibility = visibilityType
|
2019-07-31 15:01:20 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-07-25 16:56:31 +00:00
|
|
|
func (user *User) ChangePassword(newPassword string) {
|
|
|
|
user.mutex.Lock()
|
|
|
|
defer user.mutex.Unlock()
|
|
|
|
|
|
|
|
user.password = newPassword
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:31:07 +00:00
|
|
|
func (user *User) Logout(token string) {
|
2019-08-08 15:01:55 +00:00
|
|
|
user.mutex.Lock()
|
|
|
|
defer user.mutex.Unlock()
|
|
|
|
|
2019-07-24 14:31:07 +00:00
|
|
|
delete(user.Tokens, token)
|
|
|
|
}
|
|
|
|
|
2019-07-24 14:15:07 +00:00
|
|
|
func (user *User) LogoutAll() {
|
|
|
|
user.Tokens = make(map[string]Token)
|
|
|
|
}
|
2019-08-02 18:11:32 +00:00
|
|
|
|
2019-08-03 06:46:57 +00:00
|
|
|
func (user *User) JoinRoom(room internal.Room) models.ApiError {
|
2019-08-02 18:11:32 +00:00
|
|
|
memRoom := room.(*Room)
|
|
|
|
|
|
|
|
memRoom.mutex.Lock()
|
|
|
|
defer memRoom.mutex.Unlock()
|
|
|
|
|
|
|
|
for _, roomUser := range memRoom.joined {
|
|
|
|
if roomUser.ID() == user.ID() {
|
2019-08-03 06:46:57 +00:00
|
|
|
return models.NewError(models.M_BAD_STATE, "user already in room") // TODO: check code
|
2019-08-02 18:11:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
memRoom.joined = append(memRoom.joined, user)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2019-08-04 16:46:31 +00:00
|
|
|
|
2019-08-06 15:28:39 +00:00
|
|
|
func (user *User) AddRoomAlias(room internal.Room, alias string) models.ApiError {
|
|
|
|
user.backend.mutex.Lock()
|
|
|
|
defer user.backend.mutex.Unlock()
|
|
|
|
|
|
|
|
if room.Creator().ID() != user.ID() {
|
|
|
|
return models.NewError(models.M_FORBIDDEN, "only room creator can add room alias") // TODO: make room admins can use this method
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, exists := user.backend.roomAliases[alias]; exists {
|
|
|
|
return models.NewError(models.M_UNKNOWN, fmt.Sprintf("room alias #%s:%s already exists", alias, user.backend.hostname))
|
|
|
|
}
|
|
|
|
|
|
|
|
user.backend.roomAliases[alias] = room
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (user *User) DeleteRoomAlias(alias string) models.ApiError {
|
|
|
|
user.backend.mutex.Lock()
|
|
|
|
defer user.backend.mutex.Unlock()
|
|
|
|
|
|
|
|
room := user.backend.GetRoomByAlias(alias)
|
|
|
|
if room == nil {
|
|
|
|
return models.NewError(models.M_NOT_FOUND, "room not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
if room.Creator().ID() != user.ID() {
|
|
|
|
return models.NewError(models.M_FORBIDDEN, "only room creator can delete room alias") // TODO: make room admins can use this method
|
|
|
|
}
|
|
|
|
|
|
|
|
delete(user.backend.roomAliases, alias)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-08-05 15:06:46 +00:00
|
|
|
func (user *User) AddFilter(filterID string, filter common.Filter) {
|
2019-08-05 14:39:28 +00:00
|
|
|
user.mutex.Lock()
|
|
|
|
defer user.mutex.Unlock()
|
|
|
|
|
2019-08-05 15:06:46 +00:00
|
|
|
user.filters[filterID] = filter
|
2019-08-04 16:46:31 +00:00
|
|
|
}
|
|
|
|
|
2019-08-05 15:06:46 +00:00
|
|
|
func (user *User) GetFilterByID(filterID string) *common.Filter {
|
2019-08-05 14:39:28 +00:00
|
|
|
user.mutex.RLock()
|
|
|
|
defer user.mutex.RUnlock()
|
|
|
|
|
|
|
|
if filterReq, ok := user.filters[filterID]; ok {
|
|
|
|
return &filterReq
|
2019-08-04 16:46:31 +00:00
|
|
|
}
|
2019-08-05 14:39:28 +00:00
|
|
|
|
2019-08-04 16:46:31 +00:00
|
|
|
return nil
|
|
|
|
}
|