// refreshCmd handle refresh command to update connection with new // timestamp - this is only required when connection lifetime option set. func (c *client) refreshCmd(cmd *RefreshClientCommand) (*response, error) { resp := newResponse("refresh") user := cmd.User info := cmd.Info timestamp := cmd.Timestamp token := cmd.Token c.app.RLock() secret := c.app.config.Secret c.app.RUnlock() isValid := auth.CheckClientToken(secret, 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 } c.app.RLock() closeDelay := c.app.config.ExpiredConnectionCloseDelay connLifetime := c.app.config.ConnLifetime version := c.app.config.Version c.app.RUnlock() body := &ConnectBody{} body.Version = version body.Expires = connLifetime > 0 body.TTL = connLifetime body.Client = c.UID 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)*time.Second + closeDelay c.expireTimer = time.AfterFunc(duration, c.expire) } else { body.Expired = true } } resp.Body = body return resp, nil }
// 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("connect error: client already authenticated") return nil, ErrInvalidMessage } user := cmd.User info := cmd.Info c.app.RLock() secret := c.app.config.Secret insecure := c.app.config.Insecure closeDelay := c.app.config.ExpiredConnectionCloseDelay connLifetime := c.app.config.ConnLifetime version := c.app.config.Version presenceInterval := c.app.config.PresencePingInterval c.app.RUnlock() var timestamp string var token string if !insecure { timestamp = cmd.Timestamp token = cmd.Token } else { timestamp = "" token = "" } if !insecure { isValid := auth.CheckClientToken(secret, 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 body := &ConnectBody{} body.Version = version body.Expires = connLifetime > 0 body.TTL = connLifetime var timeToExpire int64 = 0 if connLifetime > 0 && !insecure { timeToExpire = c.timestamp + connLifetime - time.Now().Unix() if timeToExpire <= 0 { body.Expired = true resp.Body = body return resp, nil } } c.authenticated = true c.defaultInfo = []byte(info) c.Channels = map[Channel]bool{} c.channelInfo = map[Channel][]byte{} if c.staleTimer != nil { c.staleTimer.Stop() } c.presenceTimer = time.AfterFunc(presenceInterval, c.updatePresence) 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.UID, c.User) } if timeToExpire > 0 { duration := closeDelay + time.Duration(timeToExpire)*time.Second c.expireTimer = time.AfterFunc(duration, c.expire) } body.Client = c.UID 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 }