From 207503185e84acae13a0a496f2498cff28e7defe Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Fri, 15 Nov 2024 12:25:28 -0500 Subject: [PATCH] MM-61012 Add special handling to OS detection for mobile apps (#29139) * Stop recording unknown platforms as "Windows" in Sessions table * Add more tests to user_agent_test.go * MM-61012 Add special handling to OS detection for mobile apps --------- Co-authored-by: Mattermost Build --- server/channels/app/login.go | 4 +-- server/channels/app/user_agent.go | 30 +++++++++++++--- server/channels/app/user_agent_test.go | 49 ++++++++++++++++++++++++-- 3 files changed, 75 insertions(+), 8 deletions(-) diff --git a/server/channels/app/login.go b/server/channels/app/login.go index 1961a47c47..28f8320f88 100644 --- a/server/channels/app/login.go +++ b/server/channels/app/login.go @@ -193,8 +193,8 @@ func (a *App) DoLogin(c request.CTX, w http.ResponseWriter, r *http.Request, use ua := uasurfer.Parse(r.UserAgent()) - plat := getPlatformName(ua) - os := getOSName(ua) + plat := getPlatformName(ua, r.UserAgent()) + os := getOSName(ua, r.UserAgent()) bname := getBrowserName(ua, r.UserAgent()) bversion := getBrowserVersion(ua, r.UserAgent()) diff --git a/server/channels/app/user_agent.go b/server/channels/app/user_agent.go index 37a08cb607..3e7ad6e756 100644 --- a/server/channels/app/user_agent.go +++ b/server/channels/app/user_agent.go @@ -13,7 +13,7 @@ import ( const maxUserAgentVersionLength = 128 var platformNames = map[uasurfer.Platform]string{ - uasurfer.PlatformUnknown: "Windows", + uasurfer.PlatformUnknown: "Unknown", uasurfer.PlatformWindows: "Windows", uasurfer.PlatformMac: "Macintosh", uasurfer.PlatformLinux: "Linux", @@ -24,9 +24,19 @@ var platformNames = map[uasurfer.Platform]string{ uasurfer.PlatformWindowsPhone: "Windows Phone", } -func getPlatformName(ua *uasurfer.UserAgent) string { +func getPlatformName(ua *uasurfer.UserAgent, userAgentString string) string { platform := ua.OS.Platform + if platform == uasurfer.PlatformUnknown && strings.Contains(userAgentString, "Mattermost Mobile/") { + if strings.Contains(userAgentString, "iPhone") { + platform = uasurfer.PlatformiPhone + } else if strings.Contains(userAgentString, "iPad") { + platform = uasurfer.PlatformiPad + } else { + platform = uasurfer.PlatformLinux + } + } + name, ok := platformNames[platform] if !ok { return platformNames[uasurfer.PlatformUnknown] @@ -48,7 +58,7 @@ var osNames = map[uasurfer.OSName]string{ uasurfer.OSLinux: "Linux", } -func getOSName(ua *uasurfer.UserAgent) string { +func getOSName(ua *uasurfer.UserAgent, userAgentString string) string { os := ua.OS if os.Name == uasurfer.OSWindows { @@ -77,7 +87,19 @@ func getOSName(ua *uasurfer.UserAgent) string { } } - name, ok := osNames[os.Name] + osName := os.Name + + if osName == uasurfer.OSUnknown && strings.Contains(userAgentString, "Mattermost Mobile/") { + if strings.Contains(userAgentString, "iPhone") { + osName = uasurfer.OSiOS + } else if strings.Contains(userAgentString, "iPad") { + osName = uasurfer.OSiOS + } else { + osName = uasurfer.OSAndroid + } + } + + name, ok := osNames[osName] if ok { return name } diff --git a/server/channels/app/user_agent_test.go b/server/channels/app/user_agent_test.go index 214a75eb1a..0f975ae163 100644 --- a/server/channels/app/user_agent_test.go +++ b/server/channels/app/user_agent_test.go @@ -35,6 +35,15 @@ var testUserAgents = []testUserAgent{ {"Safari Mobile", "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B137 Safari/601.1"}, {"Mobile App", "Mattermost Mobile/2.7.0+482 (Android; 13; sdk_gphone64_arm64)"}, {"Mobile App", "Mattermost Mobile/233.234441.341234223421341234529099823109834440981234+abcdef3214eafeabc3242331129857301afesfffff1930a84e4bd2348fe129ac1309bd929dca3419af934bfe3089fcd (Android; 13; sdk_gphone64_arm64)"}, + {"Firefox (Mac)", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0"}, + {"Desktop App (Mac)", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.127 Electron/31.2.1 Safari/537.36 Mattermost/5.9.0"}, + {"Mobile App (Android, Samsung Galaxy Fold Z)", "Mattermost Mobile/2.20.0+6000556 (samsung/q4qcsx/q4q:14/UP1A.231005.007/F936WVLU4FXE3:user/release-keys; 14; SM-F936W)"}, + {"Chrome (Android)", "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Mobile Safari/537.36"}, + {"iOS App (iPhone 13)", "Mattermost Mobile/2.20.0+556 (iOS; 17.5.1; iPhone 13)"}, + {"Safari (iPhone 13)", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1"}, + {"iOS App (iPad 11 Pro)", "Mattermost Mobile/2.21.0+567 (iPadOS; 17.6.1; iPad Pro (11-inch) (1st generation))"}, + {"Safari (iPad 11 Pro, default)", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15"}, + {"Safari (iPad 11 Pro, requesting mobile site)", "Mozilla/5.0 (iPad; CPU OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1"}, } func TestGetPlatformName(t *testing.T) { @@ -57,13 +66,22 @@ func TestGetPlatformName(t *testing.T) { "iPhone", "Linux", "Linux", + "Macintosh", + "Macintosh", + "Linux", + "Linux", + "iPhone", + "iPhone", + "iPad", + "Macintosh", // By default, the iPad pretends to be a desktop Mac when opening web pages + "iPad", } for i, userAgent := range testUserAgents { t.Run(fmt.Sprintf("GetPlatformName_%v", i), func(t *testing.T) { ua := uasurfer.Parse(userAgent.UserAgent) - actual := getPlatformName(ua) + actual := getPlatformName(ua, userAgent.UserAgent) assert.Equal(t, expected[i], actual) }) } @@ -89,13 +107,22 @@ func TestGetOSName(t *testing.T) { "iOS", "Android", "Android", + "Mac OS", + "Mac OS", + "Android", + "Android", + "iOS", + "iOS", + "iOS", + "Mac OS", // By default, the iPad pretends to be a desktop Mac when opening web pages + "iOS", } for i, userAgent := range testUserAgents { t.Run(fmt.Sprintf("GetOSName_%v", i), func(t *testing.T) { ua := uasurfer.Parse(userAgent.UserAgent) - actual := getOSName(ua) + actual := getOSName(ua, userAgent.UserAgent) assert.Equal(t, expected[i], actual) }) } @@ -121,6 +148,15 @@ func TestGetBrowserName(t *testing.T) { "Safari", "Mobile App", "Mobile App", + "Firefox", + "Desktop App", + "Mobile App", + "Chrome", + "Mobile App", + "Safari", + "Mobile App", + "Safari", + "Safari", } for i, userAgent := range testUserAgents { @@ -153,6 +189,15 @@ func TestGetBrowserVersion(t *testing.T) { "9.0", "2.7.0+482", "233.234441.341234223421341234529099823109834440981234+abcdef3214eafeabc3242331129857301afesfffff1930a84e4bd2348fe129ac1309bd929d", // cut off at len 128 + "132.0", + "5.9.0", + "2.20.0+6000556", + "129.0", + "2.20.0+556", + "17.5", + "2.21.0+567", + "17.6", + "17.6", } for i, userAgent := range testUserAgents {