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>
208 lines
5.4 KiB
Go
208 lines
5.4 KiB
Go
// Copyright (c) 2024 Mattermost Community Enterprise
|
|
// Push Proxy Authentication Token Implementation
|
|
|
|
package push_proxy
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
"github.com/mattermost/mattermost/server/public/shared/mlog"
|
|
"github.com/mattermost/mattermost/server/public/shared/request"
|
|
ejobs "github.com/mattermost/mattermost/server/v8/einterfaces/jobs"
|
|
)
|
|
|
|
// PushProxyConfig holds configuration for the push proxy interface
|
|
type PushProxyConfig struct {
|
|
Config func() *model.Config
|
|
Logger mlog.LoggerIFace
|
|
}
|
|
|
|
// PushProxyImpl implements the PushProxyInterface
|
|
type PushProxyImpl struct {
|
|
config func() *model.Config
|
|
logger mlog.LoggerIFace
|
|
|
|
authToken string
|
|
mutex sync.RWMutex
|
|
|
|
// For the worker
|
|
stopChan chan struct{}
|
|
jobChan chan model.Job
|
|
}
|
|
|
|
// NewPushProxyInterface creates a new push proxy interface
|
|
func NewPushProxyInterface(cfg *PushProxyConfig) *PushProxyImpl {
|
|
return &PushProxyImpl{
|
|
config: cfg.Config,
|
|
logger: cfg.Logger,
|
|
stopChan: make(chan struct{}),
|
|
jobChan: make(chan model.Job, 1),
|
|
}
|
|
}
|
|
|
|
// GetAuthToken returns the current auth token
|
|
func (pp *PushProxyImpl) GetAuthToken() string {
|
|
pp.mutex.RLock()
|
|
defer pp.mutex.RUnlock()
|
|
return pp.authToken
|
|
}
|
|
|
|
// GenerateAuthToken generates and stores a new authentication token
|
|
func (pp *PushProxyImpl) GenerateAuthToken() *model.AppError {
|
|
pp.mutex.Lock()
|
|
defer pp.mutex.Unlock()
|
|
|
|
// Generate a cryptographically secure random token
|
|
tokenBytes := make([]byte, 32)
|
|
if _, err := rand.Read(tokenBytes); err != nil {
|
|
return model.NewAppError("GenerateAuthToken", "push_proxy.token_generation_failed", nil, err.Error(), http.StatusInternalServerError)
|
|
}
|
|
|
|
pp.authToken = hex.EncodeToString(tokenBytes)
|
|
|
|
pp.logger.Info("Generated new push proxy authentication token")
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeleteAuthToken deletes the stored authentication token
|
|
func (pp *PushProxyImpl) DeleteAuthToken() *model.AppError {
|
|
pp.mutex.Lock()
|
|
defer pp.mutex.Unlock()
|
|
|
|
pp.authToken = ""
|
|
|
|
pp.logger.Info("Deleted push proxy authentication token")
|
|
|
|
return nil
|
|
}
|
|
|
|
// MakeWorker creates a worker for the auth token generation job
|
|
func (pp *PushProxyImpl) MakeWorker() model.Worker {
|
|
return &PushProxyWorker{
|
|
pushProxy: pp,
|
|
stopChan: pp.stopChan,
|
|
jobChan: pp.jobChan,
|
|
}
|
|
}
|
|
|
|
// MakeScheduler creates a scheduler for the auth token generation job
|
|
func (pp *PushProxyImpl) MakeScheduler() ejobs.Scheduler {
|
|
return &PushProxyScheduler{
|
|
pushProxy: pp,
|
|
}
|
|
}
|
|
|
|
// PushProxyWorker implements model.Worker for push proxy token management
|
|
type PushProxyWorker struct {
|
|
pushProxy *PushProxyImpl
|
|
stopChan chan struct{}
|
|
jobChan chan model.Job
|
|
}
|
|
|
|
// Run starts the worker
|
|
func (w *PushProxyWorker) Run() {
|
|
w.pushProxy.logger.Debug("Push proxy worker started")
|
|
|
|
for {
|
|
select {
|
|
case <-w.stopChan:
|
|
w.pushProxy.logger.Debug("Push proxy worker stopped")
|
|
return
|
|
case job := <-w.jobChan:
|
|
w.pushProxy.logger.Info("Processing push proxy job",
|
|
mlog.String("job_id", job.Id),
|
|
)
|
|
|
|
// Generate a new auth token
|
|
if err := w.pushProxy.GenerateAuthToken(); err != nil {
|
|
w.pushProxy.logger.Error("Failed to generate push proxy auth token",
|
|
mlog.String("job_id", job.Id),
|
|
mlog.Err(err),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Stop stops the worker
|
|
func (w *PushProxyWorker) Stop() {
|
|
w.pushProxy.logger.Debug("Stopping push proxy worker")
|
|
close(w.stopChan)
|
|
}
|
|
|
|
// JobChannel returns the job channel
|
|
func (w *PushProxyWorker) JobChannel() chan<- model.Job {
|
|
return w.jobChan
|
|
}
|
|
|
|
// IsEnabled checks if the worker is enabled
|
|
func (w *PushProxyWorker) IsEnabled(cfg *model.Config) bool {
|
|
// Push proxy is enabled if push notification server is configured
|
|
if cfg.EmailSettings.PushNotificationServer == nil {
|
|
return false
|
|
}
|
|
return *cfg.EmailSettings.PushNotificationServer != ""
|
|
}
|
|
|
|
// PushProxyScheduler implements ejobs.Scheduler for push proxy token management
|
|
type PushProxyScheduler struct {
|
|
pushProxy *PushProxyImpl
|
|
}
|
|
|
|
// Enabled checks if the scheduler is enabled
|
|
func (s *PushProxyScheduler) Enabled(cfg *model.Config) bool {
|
|
// Push proxy scheduler is enabled if push notification server is configured
|
|
if cfg.EmailSettings.PushNotificationServer == nil {
|
|
return false
|
|
}
|
|
return *cfg.EmailSettings.PushNotificationServer != ""
|
|
}
|
|
|
|
// NextScheduleTime returns the next time the job should be scheduled
|
|
func (s *PushProxyScheduler) NextScheduleTime(cfg *model.Config, now time.Time, pendingJobs bool, lastSuccessfulJob *model.Job) *time.Time {
|
|
// If there's a pending job, don't schedule another one
|
|
if pendingJobs {
|
|
return nil
|
|
}
|
|
|
|
// Schedule token refresh every 24 hours
|
|
if lastSuccessfulJob == nil {
|
|
// No previous job, schedule immediately
|
|
nextTime := now.Add(time.Minute)
|
|
return &nextTime
|
|
}
|
|
|
|
// Calculate next schedule based on last successful job
|
|
lastJobTime := time.Unix(lastSuccessfulJob.LastActivityAt/1000, 0)
|
|
nextTime := lastJobTime.Add(24 * time.Hour)
|
|
|
|
if nextTime.Before(now) {
|
|
nextTime = now.Add(time.Minute)
|
|
}
|
|
|
|
return &nextTime
|
|
}
|
|
|
|
// ScheduleJob schedules a push proxy job
|
|
func (s *PushProxyScheduler) ScheduleJob(rctx request.CTX, cfg *model.Config, pendingJobs bool, lastSuccessfulJob *model.Job) (*model.Job, *model.AppError) {
|
|
// Create a new job
|
|
job := &model.Job{
|
|
Id: model.NewId(),
|
|
Type: "push_proxy_auth_token",
|
|
Status: model.JobStatusPending,
|
|
CreateAt: model.GetMillis(),
|
|
}
|
|
|
|
s.pushProxy.logger.Info("Scheduled push proxy auth token job",
|
|
mlog.String("job_id", job.Id),
|
|
)
|
|
|
|
return job, nil
|
|
}
|