mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 08:44:07 -04:00
Merge pull request #58739 from chandrika1993/fix/issue-50502
fix(settings): correctly detect Chrome on Android in devices & sessions
This commit is contained in:
commit
4a88f9316b
6 changed files with 128 additions and 43 deletions
55
apps/settings/src/components/AuthToken.spec.ts
Normal file
55
apps/settings/src/components/AuthToken.spec.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { detect } from '../utils/userAgentDetect.ts'
|
||||
|
||||
describe('Android Chrome detection', () => {
|
||||
it('modern Android Chrome (no Build/ string, post-2021) should match androidChrome', () => {
|
||||
const ua = 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Mobile Safari/537.36'
|
||||
expect(detect(ua)).toEqual({
|
||||
id: 'androidChrome',
|
||||
version: '132',
|
||||
})
|
||||
})
|
||||
|
||||
it('legacy Android Chrome (with Build/ string, pre-2021) should match androidChrome', () => {
|
||||
const ua = 'Mozilla/5.0 (Linux; Android 10; SM-G973F Build/QP1A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36'
|
||||
expect(detect(ua)).toEqual({
|
||||
id: 'androidChrome',
|
||||
version: '130',
|
||||
})
|
||||
})
|
||||
|
||||
it('Android Chrome on tablet (no "Mobile" in UA) should match androidChrome', () => {
|
||||
const ua = 'Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36'
|
||||
expect(detect(ua)).toEqual({
|
||||
id: 'androidChrome',
|
||||
version: '131',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Desktop Chrome regression tests', () => {
|
||||
it('Desktop Chrome on Linux should still match chrome', () => {
|
||||
const ua = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36'
|
||||
expect(detect(ua)).toEqual({
|
||||
id: 'chrome',
|
||||
version: '132',
|
||||
os: 'Linux',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('Desktop Firefox regression tests', () => {
|
||||
it('Desktop Firefox on Linux should still match firefox', () => {
|
||||
const ua = 'Mozilla/5.0 (X11; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0'
|
||||
expect(detect(ua)).toEqual({
|
||||
id: 'firefox',
|
||||
version: '124',
|
||||
os: 'Linux',
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -100,35 +100,8 @@ import NcDateTime from '@nextcloud/vue/components/NcDateTime'
|
|||
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
|
||||
import NcTextField from '@nextcloud/vue/components/NcTextField'
|
||||
import { TokenType, useAuthTokenStore } from '../store/authtoken.ts'
|
||||
import { detect } from '../utils/userAgentDetect.ts'
|
||||
|
||||
// When using capture groups the following parts are extracted the first is used as the version number, the second as the OS
|
||||
const userAgentMap = {
|
||||
ie: /(?:MSIE|Trident|Trident\/7.0; rv)[ :](\d+)/,
|
||||
// Microsoft Edge User Agent from https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
|
||||
edge: /^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[0-9.]+ (?:Mobile Safari|Safari)\/[0-9.]+ Edge\/[0-9.]+$/,
|
||||
// Firefox User Agent from https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference
|
||||
firefox: /^Mozilla\/5\.0 \([^)]*(Windows|OS X|Linux)[^)]+\) Gecko\/[0-9.]+ Firefox\/(\d+)(?:\.\d)?$/,
|
||||
// Chrome User Agent from https://developer.chrome.com/multidevice/user-agent
|
||||
chrome: /^Mozilla\/5\.0 \([^)]*(Windows|OS X|Linux)[^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/(\d+)[0-9.]+ (?:Mobile Safari|Safari)\/[0-9.]+$/,
|
||||
// Safari User Agent from http://www.useragentstring.com/pages/Safari/
|
||||
safari: /^Mozilla\/5\.0 \([^)]*(Windows|OS X)[^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)(?: Version\/([0-9]+)[0-9.]+)? Safari\/[0-9.A-Z]+$/,
|
||||
// Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
|
||||
androidChrome: /Android.*(?:; (.*) Build\/).*Chrome\/(\d+)[0-9.]+/,
|
||||
iphone: / *CPU +iPhone +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */,
|
||||
ipad: /\(iPad; *CPU +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */,
|
||||
iosClient: /^Mozilla\/5\.0 \(iOS\) (?:ownCloud|Nextcloud)-iOS.*$/,
|
||||
androidClient: /^Mozilla\/5\.0 \(Android\) (?:ownCloud|Nextcloud)-android.*$/,
|
||||
iosTalkClient: /^Mozilla\/5\.0 \(iOS\) Nextcloud-Talk.*$/,
|
||||
androidTalkClient: /^Mozilla\/5\.0 \(Android\) Nextcloud-Talk.*$/,
|
||||
// DAVx5/3.3.8-beta2-gplay (2021/01/02; dav4jvm; okhttp/4.9.0) Android/10
|
||||
davx5: /DAV(?:droid|x5)\/([^ ]+)/,
|
||||
// Mozilla/5.0 (U; Linux; Maemo; Jolla; Sailfish; like Android 4.3) AppleWebKit/538.1 (KHTML, like Gecko) WebPirate/2.0 like Mobile Safari/538.1 (compatible)
|
||||
webPirate: /(Sailfish).*WebPirate\/(\d+)/,
|
||||
// Mozilla/5.0 (Maemo; Linux; U; Jolla; Sailfish; Mobile; rv:31.0) Gecko/31.0 Firefox/31.0 SailfishBrowser/1.0
|
||||
sailfishBrowser: /(Sailfish).*SailfishBrowser\/(\d+)/,
|
||||
// Neon 1.0.0+1
|
||||
neon: /Neon \d+\.\d+\.\d+\+\d+/,
|
||||
}
|
||||
const nameMap = {
|
||||
edge: 'Microsoft Edge',
|
||||
firefox: 'Firefox',
|
||||
|
|
@ -203,18 +176,7 @@ export default defineComponent({
|
|||
}
|
||||
}
|
||||
|
||||
for (const client in userAgentMap) {
|
||||
const matches = this.token.name.match(userAgentMap[client])
|
||||
if (matches) {
|
||||
return {
|
||||
id: client,
|
||||
os: matches[2] && matches[1],
|
||||
version: matches[2] ?? matches[1],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
return detect(this.token.name)
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
33
apps/settings/src/utils/userAgentDetect.ts
Normal file
33
apps/settings/src/utils/userAgentDetect.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { userAgentMap } from './userAgentMap.ts'
|
||||
|
||||
export interface DetectedUserAgent {
|
||||
id: string
|
||||
version?: string
|
||||
os?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the client from a user agent string.
|
||||
*
|
||||
* @param ua Raw user agent string
|
||||
* @return Detected client information or null if unknown
|
||||
*/
|
||||
export function detect(ua: string): DetectedUserAgent | null {
|
||||
for (const id in userAgentMap) {
|
||||
const matches = ua.match(userAgentMap[id])
|
||||
if (matches) {
|
||||
return {
|
||||
id,
|
||||
version: matches[2] ?? matches[1],
|
||||
os: matches[2] && matches[1],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
35
apps/settings/src/utils/userAgentMap.ts
Normal file
35
apps/settings/src/utils/userAgentMap.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// When using capture groups the following parts are extracted
|
||||
// the first is used as the version number, the second as the OS
|
||||
// Exception: single-group regexes (ie, androidChrome) use the first group as the version.
|
||||
export const userAgentMap = {
|
||||
ie: /(?:MSIE|Trident|Trident\/7.0; rv)[ :](\d+)/,
|
||||
// Microsoft Edge User Agent from https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
|
||||
edge: /^Mozilla\/5\.0 \([^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/[0-9.]+ (?:Mobile Safari|Safari)\/[0-9.]+ Edge\/[0-9.]+$/,
|
||||
// Firefox User Agent from https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference
|
||||
firefox: /^Mozilla\/5\.0 \((?![^)]*Android)[^)]*(Windows|OS X|Linux)[^)]+\) Gecko\/[0-9.]+ Firefox\/(\d+)(?:\.\d)?$/,
|
||||
// Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
|
||||
androidChrome: /^Mozilla\/5\.0 \(Linux; Android[^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/(\d+)[0-9.]+ (?:Mobile )?Safari\/[0-9.]+$/,
|
||||
// Chrome User Agent from https://developer.chrome.com/multidevice/user-agent
|
||||
chrome: /^Mozilla\/5\.0 \((?![^)]*Android)[^)]*(Windows|OS X|Linux)[^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\) Chrome\/(\d+)[0-9.]+ (?:Mobile Safari|Safari)\/[0-9.]+$/,
|
||||
// Safari User Agent from http://www.useragentstring.com/pages/Safari/
|
||||
safari: /^Mozilla\/5\.0 \([^)]*(Windows|OS X)[^)]+\) AppleWebKit\/[0-9.]+ \(KHTML, like Gecko\)(?: Version\/([0-9]+)[0-9.]+)? Safari\/[0-9.A-Z]+$/,
|
||||
iphone: / *CPU +iPhone +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */,
|
||||
ipad: /\(iPad; *CPU +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */,
|
||||
iosClient: /^Mozilla\/5\.0 \(iOS\) (?:ownCloud|Nextcloud)-iOS.*$/,
|
||||
androidClient: /^Mozilla\/5\.0 \(Android\) (?:ownCloud|Nextcloud)-android.*$/,
|
||||
iosTalkClient: /^Mozilla\/5\.0 \(iOS\) Nextcloud-Talk.*$/,
|
||||
androidTalkClient: /^Mozilla\/5\.0 \(Android\) Nextcloud-Talk.*$/,
|
||||
// DAVx5/3.3.8-beta2-gplay (2021/01/02; dav4jvm; okhttp/4.9.0) Android/10
|
||||
davx5: /DAV(?:droid|x5)\/([^ ]+)/,
|
||||
// Mozilla/5.0 (U; Linux; Maemo; Jolla; Sailfish; like Android 4.3) AppleWebKit/538.1 (KHTML, like Gecko) WebPirate/2.0 like Mobile Safari/538.1 (compatible)
|
||||
webPirate: /(Sailfish).*WebPirate\/(\d+)/,
|
||||
// Mozilla/5.0 (Maemo; Linux; U; Jolla; Sailfish; Mobile; rv:31.0) Gecko/31.0 Firefox/31.0 SailfishBrowser/1.0
|
||||
sailfishBrowser: /(Sailfish).*SailfishBrowser\/(\d+)/,
|
||||
// Neon 1.0.0+1
|
||||
neon: /Neon \d+\.\d+\.\d+\+\d+/,
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue