All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- 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>
69 lines
1.7 KiB
Cheetah
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 ""
|
|
}
|
|
}
|