Full Mattermost server source with integrated Community Enterprise features. Includes vendor directory for offline/air-gapped builds. Structure: - enterprise-impl/: Enterprise feature implementations - enterprise-community/: Init files that register implementations - enterprise/: Bridge imports (community_imports.go) - vendor/: All dependencies for offline builds Build (online): go build ./cmd/mattermost Build (offline/air-gapped): go build -mod=vendor ./cmd/mattermost 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
package dtos
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const gracePeriod = 10 * time.Minute
|
|
const metadataPlaceHolder = "channel-metadata:publishers"
|
|
const occupancy = "[?occupancy=metrics.publishers]"
|
|
|
|
// Token dto
|
|
type Token struct {
|
|
Token string `json:"token"`
|
|
PushEnabled bool `json:"pushEnabled"`
|
|
}
|
|
|
|
// TokenPayload payload dto
|
|
type TokenPayload struct {
|
|
Capabilitites string `json:"x-ably-capability"`
|
|
Exp int64 `json:"exp"`
|
|
Iat int64 `json:"iat"`
|
|
}
|
|
|
|
// ParsedCapabilities capabilities
|
|
type ParsedCapabilities map[string][]string
|
|
|
|
func isMetadataType(capabilities []string) bool {
|
|
for _, capability := range capabilities {
|
|
if capability == metadataPlaceHolder {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ChannelList grabs the channel list from capabilities
|
|
func (t *Token) ChannelList() ([]string, error) {
|
|
if !t.PushEnabled || t.Token == "" {
|
|
return nil, errors.New("Push disabled or no token set")
|
|
}
|
|
|
|
tokenParts := strings.Split(t.Token, ".")
|
|
if len(tokenParts) < 2 {
|
|
return nil, errors.New("Cannot decode token")
|
|
}
|
|
decodedPayload, err := base64.RawURLEncoding.DecodeString(tokenParts[1])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var parsedPayload TokenPayload
|
|
err = json.Unmarshal(decodedPayload, &parsedPayload)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var parsedCapabilities ParsedCapabilities
|
|
err = json.Unmarshal([]byte(parsedPayload.Capabilitites), &parsedCapabilities)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
channelList := make([]string, 0, len(parsedCapabilities))
|
|
for channelName := range parsedCapabilities {
|
|
if isMetadataType(parsedCapabilities[channelName]) {
|
|
channelList = append(channelList, fmt.Sprintf("%s%s", occupancy, channelName))
|
|
} else {
|
|
channelList = append(channelList, channelName)
|
|
}
|
|
}
|
|
|
|
return channelList, nil
|
|
}
|
|
|
|
// CalculateNextTokenExpiration calculates next token expiration
|
|
func (t *Token) CalculateNextTokenExpiration() (time.Duration, error) {
|
|
if !t.PushEnabled || t.Token == "" {
|
|
return 0, errors.New("Push disabled or no token set")
|
|
}
|
|
|
|
tokenParts := strings.Split(t.Token, ".")
|
|
if len(tokenParts) < 2 {
|
|
return 0, errors.New("Cannot decode token")
|
|
}
|
|
decodedPayload, err := base64.RawURLEncoding.DecodeString(tokenParts[1])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var parsedPayload TokenPayload
|
|
err = json.Unmarshal(decodedPayload, &parsedPayload)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
tokenDuration := parsedPayload.Exp - parsedPayload.Iat
|
|
return time.Duration(tokenDuration)*time.Second - gracePeriod, nil
|
|
}
|