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 (e roomsEndpoint) handlePutState(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { room, user, err := e.getRoomAndUser(req, params) if err != nil { WriteJsonResponseWithStatus(rw, err) return } eventType := params[1].Value stateKey := "" if len(params) > 2 { stateKey = params[2].Value } var content ct.TypedContent switch eventType { case types.EventTypeMembership: content = &types.MembershipEventContent{} case types.EventTypeName: content = &types.NameEventContent{} case types.EventTypeTopic: content = &types.TopicEventContent{} case types.EventTypePowerLevels: content = &types.PowerLevelsEventContent{} case types.EventTypeJoinRules: content = &types.JoinRulesEventContent{} } var jsonErr error if content != nil { jsonErr = json.NewDecoder(req.Body).Decode(content) } else { genericContent := types.NewGenericContent(map[string]interface{}{}, eventType) content = genericContent jsonErr = json.NewDecoder(req.Body).Decode(&genericContent.Content) } if jsonErr != nil { switch err := jsonErr.(type) { case *json.SyntaxError: msg := fmt.Sprintf("error at [%d]: %s", err.Offset, err.Error()) WriteJsonResponseWithStatus(rw, types.NotJsonError(msg)) case *json.UnmarshalTypeError: msg := fmt.Sprintf("error at [%d]: expected type %s but got %s", err.Offset, err.Type, err.Value) WriteJsonResponseWithStatus(rw, types.BadJsonError(msg)) default: WriteJsonResponseWithStatus(rw, types.BadJsonError(err.Error())) } return } state, err := e.roomService.SetState(room, user, content, stateKey) if err != nil { WriteJsonResponseWithStatus(rw, err) return } res := eventIdResponse{state.EventId} WriteJsonResponse(rw, 200, res) }
func (e authEndpoint) postLogin(req *http.Request, body *authRequest) interface{} { switch body.Type { case LoginTypePassword: hostname := strings.Split(req.Host, ":")[0] return e.loginWithPassword(hostname, body) } return types.BadJsonError(fmt.Sprintf("Missing or invalid login type: '%s'", body.Type)) }
func (e eventsEndpoint) getSingleEvent(req *http.Request, params httprouter.Params) interface{} { authedUser, err := readAccessToken(e.userService, e.tokenService, req) if err != nil { return err } eventId, parseErr := ct.ParseEventId(params[0].Value) if parseErr != nil { return types.BadJsonError(parseErr.Error()) } event, err := e.eventService.Event(authedUser, eventId) if err != nil { return err } return event }
func (e profileEndpoint) setAvatarUrl(req *http.Request, params httprouter.Params, body *avatarUrlRequest) interface{} { authedUser, err := readAccessToken(e.users, e.tokens, req) if err != nil { return err } user, err := urlParams{params}.user(0, e.users) if err != nil { return err } if body.AvatarUrl == nil { return types.BadJsonError("missing 'avatar_url'") } if _, err := e.profiles.UpdateProfile(user, authedUser, nil, body.AvatarUrl); err != nil { return err } return struct{}{} }
func (e profileEndpoint) setDisplayName(req *http.Request, params httprouter.Params, body *displayNameRequest) interface{} { authedUser, err := readAccessToken(e.users, e.tokens, req) if err != nil { return err } user, err := urlParams{params}.user(0, e.users) if err != nil { return err } if body.DisplayName == nil { return types.BadJsonError("missing 'displayname'") } if _, err := e.profiles.UpdateProfile(user, authedUser, body.DisplayName, nil); err != nil { return err } return struct{}{} }
func (e presenceEndpoint) setStatus(req *http.Request, params httprouter.Params, body *statusRequest) interface{} { authedUser, err := readAccessToken(e.users, e.tokens, req) if err != nil { return err } user, err := urlParams{params}.user(0, e.users) if err != nil { return err } if body.Presence == nil && body.StatusMessage == nil { return types.BadJsonError("empty request") } _, err = e.presences.UpdateStatus(user, authedUser, body.Presence, body.StatusMessage) if err != nil { return err } return struct{}{} }
func (e authEndpoint) registerWithPassword(hostname string, body *authRequest) interface{} { if body.Username == "" { body.Username = utils.RandomString(24) } if body.Password == "" { return types.BadJsonError("Missing or invalid password") } userId := ct.NewUserId(body.Username, hostname) err := e.userService.CreateUser(userId) if err != nil { return err } if err := e.userService.SetPassword(userId, userId, body.Password); err != nil { return err } accessToken, err := e.tokenService.NewAccessToken(userId) if err != nil { return err } return authResponse{ UserId: userId, AccessToken: accessToken.String(), } }
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 jsonHandler(i interface{}) httprouter.Handle { t := reflect.TypeOf(i) if reflect.Func != t.Kind() { panic("jsonHandler: must be a function") } if t.NumOut() != 1 { panic("jsonHandler: must return a single value") } argCount := t.NumIn() var jsonType reflect.Type firstParamIsParams := false if argCount > 0 { firstParamIsParams = t.In(0).String() == "httprouter.Params" lastParamIsParams := t.In(argCount-1).String() == "httprouter.Params" lastParamIsRequest := t.In(argCount-1).String() == "*http.Request" if !lastParamIsParams && !lastParamIsRequest { typ := t.In(argCount - 1) if typ.Kind() != reflect.Ptr { panic("jsonHandler: body argument must be a pointer type, was " + typ.String()) } jsonType = typ.Elem() } } if jsonType == nil { if t.NumIn() > 2 { panic("jsonHandler: arity must be at most 2 if no body argument is preset") } } else { if t.NumIn() > 3 { panic("jsonHandler: arity must be at most 3 if body argument is preset") } } handlerFunc := reflect.ValueOf(i) return func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { var returnValue reflect.Value var args []reflect.Value if jsonType == nil { switch argCount { case 0: args = []reflect.Value{} case 1: if firstParamIsParams { args = []reflect.Value{reflect.ValueOf(params)} } else { args = []reflect.Value{reflect.ValueOf(req)} } case 2: if firstParamIsParams { args = []reflect.Value{reflect.ValueOf(params), reflect.ValueOf(req)} } else { args = []reflect.Value{reflect.ValueOf(req), reflect.ValueOf(params)} } } } else { body := reflect.New(jsonType) if err := json.NewDecoder(req.Body).Decode(body.Interface()); err != nil { switch err := err.(type) { case *json.SyntaxError: msg := fmt.Sprintf("error at [%d]: %s", err.Offset, err.Error()) WriteJsonResponseWithStatus(rw, types.NotJsonError(msg)) case *json.UnmarshalTypeError: msg := fmt.Sprintf("error at [%d]: expected type %s but got %s", err.Offset, err.Type, err.Value) WriteJsonResponseWithStatus(rw, types.BadJsonError(msg)) default: WriteJsonResponseWithStatus(rw, types.BadJsonError(err.Error())) } return } switch argCount { case 1: args = []reflect.Value{body} case 2: if firstParamIsParams { args = []reflect.Value{reflect.ValueOf(params), body} } else { args = []reflect.Value{reflect.ValueOf(req), body} } case 3: if firstParamIsParams { args = []reflect.Value{reflect.ValueOf(params), reflect.ValueOf(req), body} } else { args = []reflect.Value{reflect.ValueOf(req), reflect.ValueOf(params), body} } } } returnValue = handlerFunc.Call(args)[0] res := returnValue.Interface() withStatus, ok := res.(WithStatus) if ok { WriteJsonResponseWithStatus(rw, withStatus) } else { WriteJsonResponse(rw, 200, res) } } }