rdev/internal/adapter/templates/templates/skeleton/pkg/auth/useragent.go.tmpl
jordan 4f01015132
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
feat: implement project access enforcement and management API
- Fix no-op RequireProjectAccess middleware to enforce project_ids
- Apply project access middleware to all project-scoped routes
- Filter GET /projects by allowed project IDs for restricted keys
- Add GET /me endpoint with key identity, scopes, and project access info
- Add PATCH /keys/{id} for partial key updates (name, scopes, project_ids, allowed_ips, expires_in)
- Add GET/POST/DELETE /projects/{id}/access for project-centric access management
- Auto-grant creating key access when using POST /project/create-and-build
- Accept grant_to_key_ids in create-and-build to grant multiple keys on project creation
- Move newProvisionerWithDeps test helper from production code to test file

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 15:38:37 -07:00

69 lines
1.7 KiB
Cheetah

package auth
import "strings"
// ParseDeviceLabel extracts a human-readable device label from a user agent string.
// Returns something like "Chrome on macOS", "Safari on iPhone", "Firefox on Windows".
func ParseDeviceLabel(userAgent string) string {
if userAgent == "" {
return "Unknown device"
}
browser := parseBrowser(userAgent)
os := parseOS(userAgent)
if browser == "" && os == "" {
return "Unknown device"
}
if browser == "" {
return os
}
if os == "" {
return browser
}
return browser + " on " + os
}
func parseBrowser(ua string) string {
// Order matters — check more specific before generic.
switch {
case strings.Contains(ua, "Edg/") || strings.Contains(ua, "Edge/"):
return "Edge"
case strings.Contains(ua, "OPR/") || strings.Contains(ua, "Opera"):
return "Opera"
case strings.Contains(ua, "Brave"):
return "Brave"
case strings.Contains(ua, "Vivaldi"):
return "Vivaldi"
case strings.Contains(ua, "Chrome/") && !strings.Contains(ua, "Chromium"):
return "Chrome"
case strings.Contains(ua, "Firefox/"):
return "Firefox"
case strings.Contains(ua, "Safari/") && !strings.Contains(ua, "Chrome"):
return "Safari"
default:
return ""
}
}
func parseOS(ua string) string {
switch {
case strings.Contains(ua, "iPhone"):
return "iPhone"
case strings.Contains(ua, "iPad"):
return "iPad"
case strings.Contains(ua, "Android"):
return "Android"
case strings.Contains(ua, "Mac OS X") || strings.Contains(ua, "Macintosh"):
return "macOS"
case strings.Contains(ua, "Windows"):
return "Windows"
case strings.Contains(ua, "Linux"):
return "Linux"
case strings.Contains(ua, "CrOS"):
return "ChromeOS"
default:
return ""
}
}