// refreshCmd handle refresh command to update connection with new // timestamp - this is only required when connection lifetime project option set. func (c *client) refreshCmd(cmd *RefreshClientCommand) (*response, error) { resp := newResponse("refresh") pk := cmd.Project user := cmd.User info := cmd.Info timestamp := cmd.Timestamp token := cmd.Token project, exists := c.app.projectByKey(pk) if !exists { return nil, ErrProjectNotFound } isValid := auth.CheckClientToken(project.Secret, string(pk), string(user), timestamp, info, token) if !isValid { logger.ERROR.Println("invalid refresh token for user", user) return nil, ErrInvalidToken } ts, err := strconv.Atoi(timestamp) if err != nil { logger.ERROR.Println(err) return nil, ErrInvalidMessage } body := &RefreshBody{} connLifetime := project.ConnLifetime if connLifetime > 0 { // connection check enabled timeToExpire := int64(ts) + connLifetime - time.Now().Unix() if timeToExpire > 0 { // connection refreshed, update client timestamp and set new expiration timeout c.timestamp = int64(ts) c.defaultInfo = []byte(info) if c.expireTimer != nil { c.expireTimer.Stop() } duration := time.Duration(timeToExpire+c.app.config.ExpiredConnectionCloseDelay) * time.Second c.expireTimer = time.AfterFunc(duration, c.expire) } else { return nil, ErrConnectionExpired } body.TTL = &connLifetime } resp.Body = body return resp, nil }
// connectCmd handles connect command from client - client must send this // command immediately after establishing Websocket or SockJS connection with // Centrifugo func (c *client) connectCmd(cmd *ConnectClientCommand) (*response, error) { resp := newResponse("connect") if c.authenticated { logger.ERROR.Println("wrong connect message: client already authenticated") return nil, ErrInvalidMessage } pk := cmd.Project user := cmd.User info := cmd.Info c.app.RLock() insecure := c.app.config.Insecure closeDelay := c.app.config.ExpiredConnectionCloseDelay c.app.RUnlock() var timestamp string var token string if !insecure { timestamp = cmd.Timestamp token = cmd.Token } else { timestamp = "" token = "" } project, exists := c.app.projectByKey(pk) if !exists { return nil, ErrProjectNotFound } if !insecure { isValid := auth.CheckClientToken(project.Secret, string(pk), string(user), timestamp, info, token) if !isValid { logger.ERROR.Println("invalid token for user", user) return nil, ErrInvalidToken } } if !insecure { ts, err := strconv.Atoi(timestamp) if err != nil { logger.ERROR.Println(err) return nil, ErrInvalidMessage } c.timestamp = int64(ts) } else { c.timestamp = time.Now().Unix() } c.User = user c.Project = pk body := &ConnectBody{} var timeToExpire int64 = 0 connLifetime := project.ConnLifetime if connLifetime > 0 && !insecure { timeToExpire := c.timestamp + connLifetime - time.Now().Unix() if timeToExpire <= 0 { body.Expired = true body.TTL = &connLifetime resp.Body = body return resp, nil } } c.authenticated = true c.defaultInfo = []byte(info) c.Channels = map[Channel]bool{} c.channelInfo = map[Channel][]byte{} go c.presencePing() err := c.app.addConn(c) if err != nil { logger.ERROR.Println(err) return nil, ErrInternalServerError } if c.app.mediator != nil { c.app.mediator.Connect(c.Project, c.UID, c.User) } if timeToExpire > 0 { duration := time.Duration(timeToExpire+closeDelay) * time.Second c.expireTimer = time.AfterFunc(duration, c.expire) } body.Client = &c.UID if connLifetime > 0 { body.TTL = &connLifetime } resp.Body = body return resp, nil }