Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
b27b2b1d
authored
Jul 27, 2026
by
CaIon
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(web): detect iPad login sessions correctly
parent
a043eef5
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
65 additions
and
14 deletions
+65
-14
web/src/features/profile/components/__tests__/login-session-utils.test.ts
+49
-7
web/src/features/profile/components/login-session-item.tsx
+6
-1
web/src/features/profile/components/login-session-utils.ts
+10
-6
No files found.
web/src/features/profile/components/login-session-utils.test.ts
→
web/src/features/profile/components/
__tests__/
login-session-utils.test.ts
View file @
b27b2b1d
...
...
@@ -21,7 +21,7 @@ import { describe, test } from 'node:test'
import
type
{
TFunction
}
from
'i18next'
import
{
loginMethodLabel
,
sessionDevice
}
from
'./login-session-utils'
import
{
loginMethodLabel
,
sessionDevice
}
from
'.
.
/login-session-utils'
const
translate
=
((
key
:
string
)
=>
key
)
as
TFunction
...
...
@@ -39,15 +39,57 @@ describe('login session presentation', () => {
)
})
test
(
'derives a stable browser and operating-system label'
,
()
=>
{
test
(
'labels iPad Safari as iOS when its user agent also mentions Mac OS X'
,
()
=>
{
const
userAgent
=
'Mozilla/5.0 (iPad; CPU OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1'
assert
.
equal
(
sessionDevice
(
userAgent
,
'Unknown device'
,
'Browser'
),
'Safari · iOS'
)
})
test
(
'labels a touch-capable current iPad session as iOS when its desktop user agent says Macintosh'
,
()
=>
{
const
userAgent
=
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15'
assert
.
equal
(
sessionDevice
(
'Mozilla/5.0 (Macintosh; Intel Mac OS X) AppleWebKit Safari/605.1.15'
,
'Unknown device'
,
'Browser'
),
sessionDevice
(
userAgent
,
'Unknown device'
,
'Browser'
,
5
),
'Safari · iOS'
)
})
test
(
'keeps touch-capable Windows Chrome sessions identifiable'
,
()
=>
{
const
userAgent
=
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36'
assert
.
equal
(
sessionDevice
(
userAgent
,
'Unknown device'
,
'Browser'
,
10
),
'Chrome · Windows'
)
})
test
(
'keeps Android Chrome sessions identifiable when their user agent mentions Linux'
,
()
=>
{
const
userAgent
=
'Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36'
assert
.
equal
(
sessionDevice
(
userAgent
,
'Unknown device'
,
'Browser'
,
5
),
'Chrome · Android'
)
})
test
(
'keeps genuine macOS Safari sessions identifiable'
,
()
=>
{
const
userAgent
=
'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15'
assert
.
equal
(
sessionDevice
(
userAgent
,
'Unknown device'
,
'Browser'
),
'Safari · macOS'
)
})
test
(
'falls back to the unknown-device label for an empty user agent'
,
()
=>
{
assert
.
equal
(
sessionDevice
(
''
,
'Unknown device'
,
'Browser'
),
'Unknown device'
...
...
web/src/features/profile/components/login-session-item.tsx
View file @
b27b2b1d
...
...
@@ -34,6 +34,10 @@ interface LoginSessionItemProps {
export
function
LoginSessionItem
({
session
,
onRevoke
}:
LoginSessionItemProps
)
{
const
{
t
}
=
useTranslation
()
const
maxTouchPoints
=
session
.
current
&&
typeof
navigator
!==
'undefined'
?
navigator
.
maxTouchPoints
:
0
return
(
<
div
className=
'flex flex-col gap-3 py-4 sm:flex-row sm:items-center'
>
...
...
@@ -46,7 +50,8 @@ export function LoginSessionItem({ session, onRevoke }: LoginSessionItemProps) {
{
sessionDevice
(
session
.
user_agent
,
t
(
'Unknown device'
),
t
(
'Browser'
)
t
(
'Browser'
),
maxTouchPoints
)
}
</
p
>
{
session
.
current
&&
<
Badge
variant=
'secondary'
>
{
t
(
'Current'
)
}
</
Badge
>
}
...
...
web/src/features/profile/components/login-session-utils.ts
View file @
b27b2b1d
...
...
@@ -21,7 +21,8 @@ import type { TFunction } from 'i18next'
export
function
sessionDevice
(
userAgent
:
string
,
unknownDevice
:
string
,
browserLabel
:
string
browserLabel
:
string
,
maxTouchPoints
=
0
):
string
{
if
(
!
userAgent
)
return
unknownDevice
let
browser
=
browserLabel
...
...
@@ -31,12 +32,15 @@ export function sessionDevice(
else
if
(
userAgent
.
includes
(
'Safari/'
))
browser
=
'Safari'
let
system
=
''
if
(
userAgent
.
includes
(
'Windows'
))
system
=
'Windows'
else
if
(
userAgent
.
includes
(
'Mac OS'
))
system
=
'macOS'
else
if
(
userAgent
.
includes
(
'Android'
))
system
=
'Android'
else
if
(
userAgent
.
includes
(
'iPhone'
)
||
userAgent
.
includes
(
'iPad'
)
)
{
const
isIPad
=
userAgent
.
includes
(
'iPad'
)
||
(
userAgent
.
includes
(
'Macintosh'
)
&&
maxTouchPoints
>
1
)
if
(
userAgent
.
includes
(
'iPhone'
)
||
isIPad
)
{
system
=
'iOS'
}
else
if
(
userAgent
.
includes
(
'Linux'
))
system
=
'Linux'
}
else
if
(
userAgent
.
includes
(
'Android'
))
system
=
'Android'
else
if
(
userAgent
.
includes
(
'Windows'
))
system
=
'Windows'
else
if
(
userAgent
.
includes
(
'Mac OS'
))
system
=
'macOS'
else
if
(
userAgent
.
includes
(
'Linux'
))
system
=
'Linux'
return
system
?
`
${
browser
}
·
${
system
}
`
:
browser
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment