func (e authEndpoint) loginWithPassword(hostname string, body *authRequest) interface{} { if body.Username == "" { return types.BadJsonError("Missing or invalid user") } if body.Password == "" { return types.BadJsonError("Missing or invalid password") } user := ct.NewUserId(body.Username, hostname) exists, err := e.userService.UserExists(user, user) if err != nil { return err } if !exists { return types.NotFoundError("user '" + user.String() + "' doesn't exist") } verified, err := e.userService.VerifyPassword(user, body.Password) if err != nil { return err } if !verified { return types.ForbiddenError("invalid credentials") } accessToken, err := e.tokenService.NewAccessToken(user) if err != nil { return err } return authResponse{ UserId: user, AccessToken: accessToken.String(), } }
func (s userService) SetPassword(user, caller ct.UserId, password string) types.Error { if user != caller { return types.ForbiddenError("can't change the password of other users") } hash, err := bcrypt.GenerateFromPassword([]byte(password), 10) if err != nil { return types.ServerError("failed to generate password: " + err.Error()) } if err := s.users.SetUserPasswordHash(user, string(hash)); err != nil { return err } return nil }
func (s roomService) allowsJoinRule(room ct.RoomId, joinRule types.JoinRule) (bool, types.Error) { state, err := s.rooms.RoomState(room, types.EventTypeJoinRules, "") if err != nil { return false, err } if state == nil { panic("room power levels are invalid or missing: " + room.String()) } joinRules, ok := state.Content.(*types.JoinRulesEventContent) if !ok { panic("invalid join rule content, was " + reflect.TypeOf(state.Content).String()) } if joinRules.JoinRule != joinRule { return false, types.ForbiddenError("room does not allow join rule: " + joinRule.String()) } return true, nil }
func (s profileService) UpdateProfile( user, caller ct.UserId, name, avatarUrl *string, ) (types.UserProfile, types.Error) { if user != caller { return types.UserProfile{}, types.ForbiddenError("can't change the profile of other users") } profile, err := s.profiles.Profile(user) if err != nil { return types.UserProfile{}, err } if name != nil { profile.DisplayName = *name } if avatarUrl != nil { profile.AvatarUrl = *avatarUrl } _, err = s.profileSink.SetUserProfile(user, profile) if err != nil { return types.UserProfile{}, err } rooms, err := s.members.Rooms(user) if err != nil { return types.UserProfile{}, err } log.Printf("GOT LE STUFF %s, %#v", user, rooms) for _, room := range rooms { membership, err := s.rooms.RoomState(room, types.EventTypeMembership, user.String()) if err != nil { log.Println("failed to get membership when updating profile: " + err.Error()) continue } content := *membership.Content.(*types.MembershipEventContent) content.UserProfile = &profile state, err := s.rooms.SetRoomState(room, user, &content, user.String()) //TODO: fix race, CAS? if err != nil { log.Println("failed to set membership when updating profile: " + err.Error()) continue } _, err = s.eventSink.Send(state) if err != nil { log.Println("failed to send event when updating profile: " + err.Error()) } } return profile, nil }
func (s roomService) State( room ct.RoomId, caller ct.UserId, eventType, stateKey string, ) (*types.State, types.Error) { membership, err := s.userMembership(room, caller) if err != nil { return nil, err } if membership != types.MembershipMember { return nil, types.ForbiddenError("cannot read room state, not a member") } state, err := s.rooms.RoomState(room, eventType, stateKey) if err != nil { return nil, err } return state, err }
func (s roomService) testPowerLevel( room ct.RoomId, user ct.UserId, powerLevelFunc func(*types.PowerLevelsEventContent) int, ) types.Error { powerLevels, err := s.powerLevels(room) if err != nil { return err } userPowerLevel, err := s.userPowerLevel(room, user) if err != nil { return err } requiredPowerLevel := powerLevelFunc(powerLevels) if userPowerLevel < requiredPowerLevel { msg := fmt.Sprintf("not enough power level to perform action (%d < %d)", userPowerLevel, requiredPowerLevel) return types.ForbiddenError(msg) } return nil }
func (s roomService) AddMessage( room ct.RoomId, caller ct.UserId, content types.TypedContent, ) (*types.Message, types.Error) { eventType := content.GetEventType() if _, ok := disallowedMessageTypes[eventType]; ok { return nil, types.ForbiddenError("sending a message event of the type " + eventType + " is not permitted") } err := s.testPowerLevel(room, caller, func(pl *types.PowerLevelsEventContent) int { if eventLevel, ok := pl.Events[eventType]; ok { return eventLevel } return pl.EventDefault }) if err != nil { return nil, err } return s.sendMessage(room, caller, content) }
func (s presenceService) UpdateStatus( user, caller ct.UserId, presence *types.Presence, statusMessage *string, ) (types.UserStatus, types.Error) { if user != caller { return types.UserStatus{}, types.ForbiddenError("can't change the presence of other users") } status, err := s.presenceProvider.Status(user) if err != nil { return types.UserStatus{}, err } if presence != nil { status.Presence = *presence } if statusMessage != nil { status.StatusMessage = *statusMessage } _, err = s.presenceEventSink.SetUserStatus(user, status) if err != nil { return types.UserStatus{}, err } return status, nil }
func (s roomService) doMembershipChange( room ct.RoomId, caller ct.UserId, user ct.UserId, membership *types.MembershipEventContent, ) (*types.State, types.Error) { log.Printf("attempting membership change of %s in %s to %s, by %s", user, room, membership.Membership, caller) currentMembership, err := s.userMembership(room, user) if err != nil { return nil, err } if currentMembership == membership.Membership { return nil, types.ForbiddenError("membership change was a no-op") } membership.UserProfile = nil switch membership.Membership { case types.MembershipNone: if currentMembership != types.MembershipBanned { return nil, types.BadJsonError("invalid or missing membership in membership change") } err = s.testPowerLevel(room, caller, func(pl *types.PowerLevelsEventContent) int { return pl.Ban }) if err != nil { return nil, err } if user == caller { return nil, types.ForbiddenError("cannot remove a ban from self") } case types.MembershipInvited: if currentMembership != types.MembershipNone { return nil, types.ForbiddenError("could not invite user to room, already have membership '" + currentMembership.String() + "'") } ok, err := s.allowsJoinRule(room, types.JoinRuleInvite) if err != nil { return nil, err } if !ok { return nil, types.ForbiddenError("room does not allow join method: " + types.JoinRuleInvite.String()) } err = s.testPowerLevel(room, caller, func(pl *types.PowerLevelsEventContent) int { return pl.Invite }) if err != nil { return nil, err } case types.MembershipMember: switch currentMembership { case types.MembershipNone: ok, err := s.allowsJoinRule(room, types.JoinRulePublic) if err != nil { return nil, err } if !ok { return nil, types.ForbiddenError("room does not allow join method: " + types.JoinRuleInvite.String()) } case types.MembershipInvited: if user != caller { return nil, types.ForbiddenError("cannot force other users to join the room") } case types.MembershipKnocking: if user == caller { return nil, types.ForbiddenError("cannot let yourself in after knocking") } err = s.testPowerLevel(room, caller, func(pl *types.PowerLevelsEventContent) int { return pl.Invite }) if err != nil { return nil, err } case types.MembershipBanned: if user == caller { return nil, types.ForbiddenError("you are banned from that room") } else { return nil, types.ForbiddenError("that user is banned from this room") } } profile, err := s.profileProvider.Profile(caller) if err != nil { return nil, err } membership.UserProfile = &profile case types.MembershipKnocking: if user != caller { return nil, types.ForbiddenError("cannot force other users to knock") } if currentMembership != types.MembershipNone { return nil, types.ForbiddenError("could not knock on room, already have membership '" + currentMembership.String() + "'") } ok, err := s.allowsJoinRule(room, types.JoinRuleKnock) if err != nil { return nil, err } if !ok { return nil, types.ForbiddenError("room does not allow join method: " + types.JoinRuleKnock.String()) } case types.MembershipLeaving: if currentMembership == types.MembershipNone { return nil, types.ForbiddenError("tried to leave a room without current membership") } if currentMembership == types.MembershipBanned { return nil, types.ForbiddenError("tried to leave room with current membership '" + types.MembershipBanned.String() + "'") } if user != caller { err = s.testPowerLevel(room, caller, func(pl *types.PowerLevelsEventContent) int { return pl.Kick }) if err != nil { return nil, err } } case types.MembershipBanned: if user == caller { return nil, types.ForbiddenError("cannot ban self") } err = s.testPowerLevel(room, caller, func(pl *types.PowerLevelsEventContent) int { return pl.Ban }) if err != nil { return nil, err } } if membership.Membership == types.MembershipMember { if err := s.members.AddMember(room, user); err != nil { return nil, err } } else if currentMembership == types.MembershipMember { if err := s.members.RemoveMember(room, user); err != nil { return nil, err } } return s.setState(room, caller, membership, user.String()) }
func (s roomService) SetState( room ct.RoomId, caller ct.UserId, content types.TypedContent, stateKey string, ) (*types.State, types.Error) { userIdStateKey, parseErr := ct.ParseUserId(stateKey) isUserIdStateKey := parseErr == nil eventType := content.GetEventType() switch eventType { case types.EventTypeName: if stateKey != "" { return nil, types.ForbiddenError("state key must be empty for state " + eventType) } case types.EventTypeTopic: if stateKey != "" { return nil, types.ForbiddenError("state key must be empty for state " + eventType) } case types.EventTypeJoinRules: if stateKey != "" { return nil, types.ForbiddenError("state key must be empty for state " + eventType) } case types.EventTypePowerLevels: if stateKey != "" { return nil, types.ForbiddenError("state key must be empty for state " + eventType) } case types.EventTypeCreate: return nil, types.ForbiddenError("cannot set state " + eventType) case types.EventTypeAliases: return nil, types.ForbiddenError("cannot set state " + eventType) case types.EventTypeMembership: membership, ok := content.(*types.MembershipEventContent) if !ok || membership == nil { panic("expected membership event content, got " + reflect.TypeOf(content).String()) } if !isUserIdStateKey { return nil, types.ForbiddenError("state key must be a user id for state " + eventType) } state, err := s.doMembershipChange(room, caller, userIdStateKey, membership) if err != nil { return nil, err } return state, nil } if isUserIdStateKey && userIdStateKey != caller { return nil, types.ForbiddenError("cannot set the state of another user") } existing, err := s.rooms.RoomState(room, eventType, stateKey) if err != nil { return nil, err } if existing != nil { err := s.testPowerLevel(room, caller, func(pl *types.PowerLevelsEventContent) int { return pl.CreateState }) if err != nil { return nil, err } } err = s.testPowerLevel(room, caller, func(pl *types.PowerLevelsEventContent) int { if eventLevel, ok := pl.Events[eventType]; ok { return eventLevel } return pl.EventDefault }) if err != nil { return nil, err } return s.setState(room, caller, content, stateKey) }