Update .gitignore to include log files and database journal files. Modify go.mod to update dependencies for go-sqlite3 and cloud.google.com/go/compute/metadata. Enhance Makefile to include logging options for manager and runner commands. Introduce new job token handling in auth package and implement database migration scripts. Refactor manager and runner components to improve job processing and metadata extraction. Add support for video preview in frontend components and enhance WebSocket management for channel subscriptions.
This commit is contained in:
115
internal/auth/jobtoken.go
Normal file
115
internal/auth/jobtoken.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// JobTokenDuration is the validity period for job tokens
|
||||
const JobTokenDuration = 1 * time.Hour
|
||||
|
||||
// JobTokenClaims represents the claims in a job token
|
||||
type JobTokenClaims struct {
|
||||
JobID int64 `json:"job_id"`
|
||||
RunnerID int64 `json:"runner_id"`
|
||||
TaskID int64 `json:"task_id"`
|
||||
Exp int64 `json:"exp"` // Unix timestamp
|
||||
}
|
||||
|
||||
// jobTokenSecret is the secret used to sign job tokens
|
||||
// Generated once at startup and kept in memory
|
||||
var jobTokenSecret []byte
|
||||
|
||||
func init() {
|
||||
// Generate a random secret for signing job tokens
|
||||
// This means tokens are invalidated on server restart, which is acceptable
|
||||
// for short-lived job tokens
|
||||
jobTokenSecret = make([]byte, 32)
|
||||
if _, err := rand.Read(jobTokenSecret); err != nil {
|
||||
panic(fmt.Sprintf("failed to generate job token secret: %v", err))
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateJobToken creates a new job token for a specific job/runner/task combination
|
||||
func GenerateJobToken(jobID, runnerID, taskID int64) (string, error) {
|
||||
claims := JobTokenClaims{
|
||||
JobID: jobID,
|
||||
RunnerID: runnerID,
|
||||
TaskID: taskID,
|
||||
Exp: time.Now().Add(JobTokenDuration).Unix(),
|
||||
}
|
||||
|
||||
// Encode claims to JSON
|
||||
claimsJSON, err := json.Marshal(claims)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal claims: %w", err)
|
||||
}
|
||||
|
||||
// Create HMAC signature
|
||||
h := hmac.New(sha256.New, jobTokenSecret)
|
||||
h.Write(claimsJSON)
|
||||
signature := h.Sum(nil)
|
||||
|
||||
// Combine claims and signature: base64(claims).base64(signature)
|
||||
token := base64.RawURLEncoding.EncodeToString(claimsJSON) + "." +
|
||||
base64.RawURLEncoding.EncodeToString(signature)
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
// ValidateJobToken validates a job token and returns the claims if valid
|
||||
func ValidateJobToken(token string) (*JobTokenClaims, error) {
|
||||
// Split token into claims and signature
|
||||
var claimsB64, sigB64 string
|
||||
dotIdx := -1
|
||||
for i := len(token) - 1; i >= 0; i-- {
|
||||
if token[i] == '.' {
|
||||
dotIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if dotIdx == -1 {
|
||||
return nil, fmt.Errorf("invalid token format")
|
||||
}
|
||||
claimsB64 = token[:dotIdx]
|
||||
sigB64 = token[dotIdx+1:]
|
||||
|
||||
// Decode claims
|
||||
claimsJSON, err := base64.RawURLEncoding.DecodeString(claimsB64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid token encoding: %w", err)
|
||||
}
|
||||
|
||||
// Decode signature
|
||||
signature, err := base64.RawURLEncoding.DecodeString(sigB64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid signature encoding: %w", err)
|
||||
}
|
||||
|
||||
// Verify signature
|
||||
h := hmac.New(sha256.New, jobTokenSecret)
|
||||
h.Write(claimsJSON)
|
||||
expectedSig := h.Sum(nil)
|
||||
if !hmac.Equal(signature, expectedSig) {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
}
|
||||
|
||||
// Parse claims
|
||||
var claims JobTokenClaims
|
||||
if err := json.Unmarshal(claimsJSON, &claims); err != nil {
|
||||
return nil, fmt.Errorf("invalid claims: %w", err)
|
||||
}
|
||||
|
||||
// Check expiration
|
||||
if time.Now().Unix() > claims.Exp {
|
||||
return nil, fmt.Errorf("token expired")
|
||||
}
|
||||
|
||||
return &claims, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user