fix: Resolve mobile audio playback permission issues

- Change cookie SameSite policy from Strict to Lax (Strict blocks media subresources on mobile)
- Decouple Secure cookie flag from APP_ENV:
  - Add SECURE_COOKIES config (defaults to true in prod, but can be overridden)
  - Allows testing production builds over HTTP (home network)
- Increase gocyclo threshold to 25 to accommodate complex handlers
This commit is contained in:
rishikanthc
2025-12-16 17:21:32 -08:00
parent 400f90507e
commit 4047264a69
3 changed files with 18 additions and 12 deletions

View File

@@ -45,7 +45,7 @@ linters-settings:
- name: errorf
gocyclo:
# minimal code complexity to report, 30 by default (25 is reasonable for complex handlers)
# minimal code complexity to report, 30 by default (but we want it slightly stricter but still sane)
min-complexity: 25
goconst:

View File

@@ -1547,17 +1547,15 @@ func (h *Handler) Login(c *gin.Context) {
}
// Set access token cookie for streaming/media access
// We use Lax mode to allow top-level navigation authentication if needed, but Strict is safer for API.
// Since we use this for <audio> src which is a cross-origin-like request (even if same origin technically),
// SameSite=Strict should work for same-site.
// Use Lax mode because Strict mode blocks <audio>/<video> subresource requests on mobile browsers.
http.SetCookie(c.Writer, &http.Cookie{
Name: "scriberr_access_token",
Value: token,
Path: "/",
Expires: time.Now().Add(24 * time.Hour), // Match your token duration constant
HttpOnly: true,
Secure: h.config.IsProduction(), // Secure in production
SameSite: http.SameSiteStrictMode,
Secure: h.config.SecureCookies, // Use explicit secure flag
SameSite: http.SameSiteLaxMode,
})
response := LoginResponse{Token: token}
@@ -1589,7 +1587,7 @@ func (h *Handler) Logout(c *gin.Context) {
MaxAge: -1,
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
Secure: h.config.IsProduction(),
Secure: h.config.SecureCookies,
})
// Also clear access token
http.SetCookie(c.Writer, &http.Cookie{
@@ -1599,8 +1597,8 @@ func (h *Handler) Logout(c *gin.Context) {
Expires: time.Unix(0, 0),
MaxAge: -1,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Secure: h.config.IsProduction(),
SameSite: http.SameSiteLaxMode,
Secure: h.config.SecureCookies,
})
c.JSON(http.StatusOK, gin.H{"message": "Logged out successfully"})
}
@@ -1742,8 +1740,8 @@ func (h *Handler) Refresh(c *gin.Context) {
Path: "/",
Expires: time.Now().Add(24 * time.Hour),
HttpOnly: true,
Secure: h.config.IsProduction(),
SameSite: http.SameSiteStrictMode,
Secure: h.config.SecureCookies,
SameSite: http.SameSiteLaxMode,
})
c.JSON(http.StatusOK, RefreshTokenResponse{Token: token})
@@ -1770,7 +1768,7 @@ func (h *Handler) issueRefreshToken(c *gin.Context, userID uint) error {
MaxAge: int((14 * 24 * time.Hour).Seconds()),
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
Secure: h.config.IsProduction(),
Secure: h.config.SecureCookies,
})
return nil
}

View File

@@ -36,6 +36,7 @@ type Config struct {
// Environment configuration
Environment string
AllowedOrigins []string
SecureCookies bool // Explicit control over Secure flag (for HTTPS deployments)
// OpenAI configuration
OpenAIAPIKey string
}
@@ -47,6 +48,12 @@ func Load() *Config {
logger.Debug("No .env file found, using system environment variables")
}
// Default SecureCookies to true in production, false otherwise
defaultSecure := "false"
if strings.ToLower(getEnv("APP_ENV", "development")) == "production" {
defaultSecure = "true"
}
return &Config{
Port: getEnv("PORT", "8080"),
Host: getEnv("HOST", "0.0.0.0"),
@@ -58,6 +65,7 @@ func Load() *Config {
TranscriptsDir: getEnv("TRANSCRIPTS_DIR", "data/transcripts"),
UVPath: findUVPath(),
WhisperXEnv: getEnv("WHISPERX_ENV", "data/whisperx-env"),
SecureCookies: getEnv("SECURE_COOKIES", defaultSecure) == "true",
OpenAIAPIKey: getEnv("OPENAI_API_KEY", ""),
}
}