-
Notifications
You must be signed in to change notification settings - Fork 512
Description
How to use GitHub
- Please use the π [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to show that you are affected by the same issue.
- Please don't comment if you have no relevant information to add. It's just extra noise for everyone subscribed to this issue.
- Subscribe to receive notifications on status change and new comments.
Steps to reproduce
- Authenticate a native Talk client (iOS v23.0.1) via app-password/token authentication (no PHP session cookie).
- Join or receive a call in any conversation room.
- The client calls
POST /api/v4/call/{token}to join the call.
Expected behaviour
The call should be joined successfully (HTTP 200), just as it works in the browser for the same user, room, and Talk version.
Actual behaviour
The API returns HTTP 404. The iOS app displays:
"Anruf kann nicht angenommen werden / Unterhaltung nicht gefunden oder nicht beigetreten"
("Call cannot be accepted / Conversation not found or not joined")
This occurs 100% of the time on native clients. Browser-based calls work fine.
Root cause: Manager::getRoomForUserByToken() caches a Participant without a session in ParticipantService::$actorCache when $sessionId is null. For native app clients, TalkSession::getSessionForRoom() returns null because there is no PHP session cookie β the OCP\ISession is a stateless in-memory session that doesn't persist between requests.
Detailed trace
-
InjectionMiddleware::getLoggedInOrGuest()callsManager::getRoomForUserByToken($token, $userId, null). -
In
[getRoomForUserByToken()](https://github.com/nextcloud/spreed/blob/v23.0.1/lib/Manager.php#L700), the session LEFT JOIN is skipped because$sessionIdisnull:
if ($sessionId !== null) { // null for app-password auth β SKIPPED
$helper->selectSessionsTable($query);
$query->leftJoin('a', 'talk_sessions', 's', ...);
}- The participant is created without session data and cached:
$participant = $this->createParticipantObject($room, $row);
$this->participantService->cacheParticipant($room, $participant); // cached WITHOUT session-
Back in
getLoggedInOrGuest(),getParticipant($room, $userId)is called with default$sessionId = null. -
In
[ParticipantService::getParticipant()](https://github.com/nextcloud/spreed/blob/v23.0.1/lib/Service/ParticipantService.php#L2233), the!$sessionIdshortcut returns the cached null-session participant β the DB LEFT JOIN totalk_sessionsnever executes:
if (isset($this->actorCache[...][...][...])) {
$participant = $this->actorCache[...];
if (!$sessionId // !null β true β RETURNS CACHED WITHOUT SESSION
|| ($participant->getSession() instanceof Session
&& $participant->getSession()->getSessionId() === $sessionId)) {
return $participant;
}
}CallController::joinCall()checks$this->participant->getSession()βnullβ returns HTTP 404.
Proof
Adding debug instrumentation to joinCall() to query talk_sessions directly at the moment of the 404 shows 10 active sessions (state=1) for the user in the database. The sessions exist β they are just never loaded.
Proposed fix
In ParticipantService::getParticipant(), change the actorCache hit condition so that a null-session cached participant is not returned when the caller requests a session ($sessionId = null):
// Before:
if (!$sessionId
|| ($participant->getSession() instanceof Session
&& $participant->getSession()->getSessionId() === $sessionId)) {
return $participant;
}
// After:
if ($sessionId === false
|| ($participant->getSession() instanceof Session
&& (!$sessionId || $participant->getSession()->getSessionId() === $sessionId))) {
return $participant;
}This ensures:
$sessionId === false(caller doesn't need session) β return cached, preserving performance.$sessionId === null(caller wants any session) β only return cached if it actually has a session; otherwise fall through to DB query.$sessionId === "specific"β only return cached if it matches.
Related issues:
- API for joining a call does only work with cookiesΒ #8559 β "API for joining a call does only work with cookies"
- Re-join room when starting a call results in 404Β talk-ios#1756 β "Re-join room when starting a call results in 404"
- Try to forceReconnect on 404 when joining callΒ talk-ios#1777 β "Try to forceReconnect on 404 when joining call" (client-side workaround)
Note: The
// FIXME PROBLEMcomment at the null-$sessionIdLEFT JOIN branch ingetParticipant()suggests this area was already known to be problematic.
Talk app
Talk app version: v23.0.1
**Custom Signaling server configured: ** strukturag/nextcloud-spreed-signaling:latest
Browser
Not applicable β this bug affects native app clients only. Browser-based calls work correctly.
Microphone available: n/a
Camera available: n/a
Operating system: iOS (Talk iOS app v23.0.1)
Browser name: n/a
Browser version: n/a
Browser log
Details
n/a β native app issue, not browser-related.
Server configuration
Operating system: Docker FPM Alpine 33.0.0
Web server: Nginx (behind nginx ingress, 2 Nextcloud replicas)
Database: MariaDB Galera (3-node cluster)
Nextcloud Version: 33.0.0
List of activated apps:
Details
Enabled:
- activity: 6.0.0-dev.0
- admin_audit: 1.23.0
- app_api: 33.0.0
- approval: 3.1.0
- bruteforcesettings: 6.0.0-dev.0
- calendar: 6.2.1
- circles: 33.0.0
- cloud_federation_api: 1.17.0
- collectives: 4.0.0
- comments: 1.23.0
- contacts: 8.4.1
- contactsinteraction: 1.14.1
- dashboard: 7.13.0
- dav: 1.36.0
- deck: 1.17.0
- federatedfilesharing: 1.23.0
- federation: 1.23.0
- files: 2.5.0
- files_downloadlimit: 5.1.0-dev.0
- files_pdfviewer: 6.0.0-dev.0
- files_reminders: 1.6.0
- files_sharing: 1.25.2
- files_trashbin: 1.23.0
- files_versions: 1.26.0
- firstrunwizard: 6.0.0-dev.0
- forms: 5.2.5
- groupfolders: 21.0.6
- logreader: 6.0.0
- lookup_server_connector: 1.21.0
- mail: 5.7.2
- nextcloud_announcements: 5.0.0
- notes: 4.13.0
- notifications: 6.0.0
- notify_push: 1.3.0
- oauth2: 1.21.0
- password_policy: 5.0.0-dev.0
- photos: 6.0.0-dev.0
- privacy: 5.0.0-dev.0
- profile: 1.2.0
- provisioning_api: 1.23.0
- recommendations: 6.0.0-dev.0
- related_resources: 4.0.0-dev.0
- richdocuments: 10.1.0
- serverinfo: 5.0.0-dev.0
- settings: 1.16.0
- sharebymail: 1.23.0
- spreed: 23.0.1
- support: 5.0.0
- survey_client: 5.0.0-dev.0
- suspicious_login: 11.0.0-dev.0
- systemtags: 1.23.0
- tasks: 0.17.1
- text: 7.0.0-dev.3
- theming: 2.8.0
- twofactor_backupcodes: 1.22.0
- twofactor_totp: 15.0.0-dev.0
- updatenotification: 1.23.0
- user_ldap: 1.24.0
- user_status: 1.13.0
- viewer: 6.0.0-dev.0
- weather_status: 1.13.0
- webhook_listeners: 1.5.0
- whiteboard: 1.5.7
- workflowengine: 2.15.0
Disabled:
- encryption: 2.21.0
- files_external: 1.25.1
- twofactor_nextcloud_notification: 7.0.0
Nextcloud configuration:
Details
{
"system": {
"passwordsalt": "***REMOVED SENSITIVE VALUE***",
"secret": "***REMOVED SENSITIVE VALUE***",
"trusted_domains": [
"localhost",
"nextcloud.nextcloud-test.example.org",
"nextcloud-chart.nextcloud.svc.cluster.local"
],
"datadirectory": "***REMOVED SENSITIVE VALUE***",
"dbtype": "mysql",
"version": "33.0.0.16",
"overwrite.cli.url": "https:\/\/nextcloud.nextcloud-test.example.org",
"dbname": "***REMOVED SENSITIVE VALUE***",
"dbhost": "***REMOVED SENSITIVE VALUE***",
"dbport": "",
"dbtableprefix": "oc_",
"mysql.utf8mb4": true,
"dbuser": "***REMOVED SENSITIVE VALUE***",
"dbpassword": "***REMOVED SENSITIVE VALUE***",
"installed": true,
"instanceid": "***REMOVED SENSITIVE VALUE***",
"htaccess.RewriteBase": "\/",
"memcache.local": "\\OC\\Memcache\\APCu",
"apps_paths": [
{
"path": "\/var\/www\/html\/apps",
"url": "\/apps",
"writable": false
},
{
"path": "\/var\/www\/html\/custom_apps",
"url": "\/custom_apps",
"writable": true
}
],
"memcache.distributed": "\\OC\\Memcache\\Redis",
"memcache.locking": "\\OC\\Memcache\\Redis",
"redis": {
"host": "***REMOVED SENSITIVE VALUE***",
"password": "***REMOVED SENSITIVE VALUE***",
"port": 26379,
"masterName": "nextcloud-redis",
"sentinels": [
{
"host": "nextcloud-chart-redis.nextcloud.svc.cluster.local",
"port": 26379
}
],
"timeout": 1.5,
"read_timeout": 1.5
},
"overwriteprotocol": "https",
"upgrade.disable-web": true,
"app_install_overwrite": [
"spreed",
"mail",
"calendar",
"contacts",
"tasks",
"deck",
"notes",
"forms",
"collectives",
"whiteboard",
"richdocuments",
"groupfolders",
"user_ldap",
"twofactor_totp",
"admin_audit",
"suspicious_login",
"terms_of_service",
"approval",
"notify_push"
],
"ldapProviderFactory": "OCA\\User_LDAP\\LDAPProviderFactory",
"trusted_proxies": "***REMOVED SENSITIVE VALUE***",
"appstoreenabled": false,
"updatechecker": false,
"loglevel": 2,
"maintenance": false,
"log_type": "file",
"logfile": "\/var\/www\/html\/data\/nextcloud.log",
"default_phone_region": "DE",
"skeletondirectory": "",
"default_locale": "de_DE",
"maintenance_window_start": "1"
}
}