c3614c6333
golangci-lint flagged three errcheck: - stream_token.go: fmt.Fprintf(mac, ...) - hash.Hash never errors per documented contract, but errcheck wants explicit discard. Discard via _, _ assignment with a WHY comment. - config_test.go: os.Unsetenv calls in tests - discard the error via _ assignment. Test cleanup paths. Reviewers flagged the Fprintf one during Task 1 quality review but golangci-lint runs in a separate CI step that wasn't exercised on the per-task pushes (cancelled by subsequent push concurrency).
40 lines
1.4 KiB
Go
40 lines
1.4 KiB
Go
package api
|
|
|
|
import (
|
|
"crypto/hmac"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// SignStreamToken returns the HMAC-SHA256 hex of "<trackID>|<exp>" keyed
|
|
// by secret. The token is constant-time-comparable via VerifyStreamToken
|
|
// so it's safe to expose the verification function in handlers.
|
|
//
|
|
// trackID is the canonical track UUID. exp is the Unix time after which
|
|
// the token is invalid; the handler checks exp before serving.
|
|
//
|
|
// The secret comes from MINSTREL_STREAM_SECRET (or its auto-generated +
|
|
// persisted fallback in app_preferences). The loader lands in slice 2
|
|
// (POST /api/cast/stream-token); this file is the primitive both the
|
|
// loader and the stream handler share.
|
|
func SignStreamToken(secret []byte, trackID string, exp int64) string {
|
|
mac := hmac.New(sha256.New, secret)
|
|
// hash.Hash.Write is documented as never returning an error.
|
|
_, _ = fmt.Fprintf(mac, "%s|%d", trackID, exp)
|
|
return hex.EncodeToString(mac.Sum(nil))
|
|
}
|
|
|
|
// VerifyStreamToken returns true iff token is a valid HMAC for
|
|
// (trackID, exp) AND exp has not yet passed. Wall-clock comparison —
|
|
// callers must trust the server's clock. Uses hmac.Equal for
|
|
// constant-time compare so a timing oracle can't bias token guessing.
|
|
func VerifyStreamToken(secret []byte, trackID string, exp int64, token string) bool {
|
|
if time.Now().Unix() > exp {
|
|
return false
|
|
}
|
|
expected := SignStreamToken(secret, trackID, exp)
|
|
return hmac.Equal([]byte(expected), []byte(token))
|
|
}
|