Skip to content

feat(call): add setting to limit starting calls to specific groups - #18647

Merged
nickvergessen merged 3 commits into
nextcloud:mainfrom
pascalkienast:enh/17465/restrict-call-start-to-groups
Jul 20, 2026
Merged

nickvergessen merged 3 commits into
nextcloud:mainfrom
pascalkienast:enh/17465/restrict-call-start-to-groups

Conversation

@pascalkienast

@pascalkienast pascalkienast commented Jul 11, 2026 •

Copy link
Copy Markdown
Contributor

☑️ Resolves

🖼️ What does this PR do?

Adds a new admin setting "Limit starting calls to groups" (app config start_calls_groups, JSON array of group ids, empty by default).

  • Empty (default): current behaviour, byte-identical.
  • Groups configured: only members of those groups can start a call. Everyone else can still use Talk for chat and can join ongoing calls - exactly the gap described in Restrict video/audio call start to specific groups #17465, where the only workaround today (restricting conversation creation) also takes away chat.
Bildschirmfoto 2026-07-13 um 01 39 07

Why this matters

As described in #17465: on instances without (or with a limited) High Performance Backend, any user starting ad-hoc calls can cause significant resource and bandwidth issues, and the only workaround today (restricting conversation creation) also takes away chat. This setting lets admins keep chat open for everyone while rolling out calling gradually to selected groups.

How it works

  • Config::getAllowedStartCallGroupIds() + Config::isNotAllowedToStartCalls(Participant)
    • follows the existing start_conversations pattern. The check works on participant level (rather than user level) because room context is needed: for federated conversations the host server decides, and non-user actors (guests, email guests, federated users) can never be in a local group.
  • The check is hooked into Participant::canStartCall(), so enforcement and clients share one source of truth:
    • Enforcement: existing RestrictStartingCalls listener → ForbiddenException → OCS 403. Join-vs-start distinction (hasActiveSessionsInCall) is inherited untouched.
    • Clients: the canStartCall room property already drives the call button in Web/mobile — no client changes needed.
  • Deleted groups are removed from the setting (GroupDeletedListener).
  • The new config is part of the Talk hash so clients refresh their state on change.
  • Admin UI: group multiselect in the existing "Limit to groups" section, 1:1 the start_conversations pattern.

Semantics

  • Room moderators who are not members of an allowed group cannot start calls. The setting acts as an instance-level restriction; per-room exceptions can still be configured through the existing start_calls permission bits.
  • Guests cannot start calls while the setting is active because they cannot be members of a local group.
  • Existing listener exceptions, including password-request rooms and phone/direct dial-in flows, remain unchanged.

🧪 How to test

  1. occ config:app:set spreed start_calls_groups --value='["allowed-group"]'
  2. A user in allowed-group can start a call.
  3. A user outside the group sees the call button disabled, and POST /call/{token} returns 403.
  4. The same user can join once a call is already running.
  5. occ config:app:delete spreed start_calls_groups restores the default behaviour.

Covered by unit tests (ConfigTest, RestrictStartingCallsTest) and the integration feature callapi/limit-starting-calls.feature.

🏁 Checklist

  • ⛑️ Unit and integration tests are included
  • 📘 docs/settings.md is updated
  • 🔖 No new capability or OpenAPI change is required; clients use the existing canStartCall room property

AI

  • This PR was partly developed with AI assistance.

@nickvergessen
nickvergessen self-requested a review July 11, 2026 16:10
@nickvergessen nickvergessen added feature: settings ⚙️ Settings and config related issues feature: api 🛠️ OCS API for conversations, chats and participants feature: call 📹 Voice and video calls labels Jul 11, 2026
@nickvergessen nickvergessen added this to the ⛅ Next Major (35) milestone Jul 11, 2026
@pascalkienast
pascalkienast marked this pull request as ready for review July 11, 2026 16:13
@pascalkienast
pascalkienast force-pushed the enh/17465/restrict-call-start-to-groups branch from b07fc9d to 2b9a73a Compare July 12, 2026 23:29
@nickvergessen

Copy link
Copy Markdown
Member

Thanks for your PR, hopefully I will find time to review this later this week.

From a quick look it seems to do 2 things:

  1. Fix federated case of starting a call (403) and also when the HPB (signaling) tries to start the session when it's not allowed
  2. Add a group selection for starting a call

the first part should apply also to old versions that do not have your new feature, right?

@pascalkienast

Copy link
Copy Markdown
Contributor Author

Thanks for your PR, hopefully I will find time to review this later this week.

From a quick look it seems to do 2 things:

  1. Fix federated case of starting a call (403) and also when the HPB (signaling) tries to start the session when it's not allowed
  2. Add a group selection for starting a call

the first part should apply also to old versions that do not have your new feature, right?

Yes, exactly. Both issues can already occur when the host restricts who may start calls, for example when start_calls is set to “Moderators only”:

  • Federation: The participant’s server determines the call button state using its own start_calls setting. It does not know the host’s setting. If the host is more restrictive, the federated participant still sees an active “Start call” button. The host then returns the correct 403, but the proxying server wraps it in a CannotReachRemoteException. The user sees what looks like a connection error instead of a permission error.
  • Signaling/HPB: If the backend join path tries to mark the first participant as in-call when that participant is not allowed to start the call, Talk throws a ForbiddenException. The exception currently escapes instead of being returned as a structured backend error. SIP dial-in is one way to reach this path.

I included both fixes in this PR because I encountered these paths while testing the new group restriction. Federated attendees, anonymous guests, and email guests have no local user identity that can be checked against groups on the host. Once start_calls_groups is configured, an attempt by one of these participants to start an inactive call is therefore denied.

The permission checks would still enforce the restriction without these fixes, but affected clients would receive a misleading federation error or an unstructured signaling error. The fixes therefore also make sense independently of the feature.

I’m happy to move the two error-handling fixes into a separate PR if that would make backporting and review easier. This is my first contribution to Talk, so I’m happy to follow whatever process you prefer.

@nickvergessen

Copy link
Copy Markdown
Member

Yeah in that case it would be better to first fix the underlying bugs so we can easily test those individually and it's less troublesome to backport them.

Judging from the description and commit messages you used AI, so maybe you can ask it to extract the relevant changes

@pascalkienast

Copy link
Copy Markdown
Contributor Author

Yeah in that case it would be better to first fix the underlying bugs so we can easily test those individually and it's less troublesome to backport them.

Judging from the description and commit messages you used AI, so maybe you can ask it to extract the relevant changes

Done - extracted the two fixes into #18664, each as its own commit (federation 403 pass-through and the structured signaling error), including the corresponding docs/call.md and OpenAPI updates.

Once that PR is merged, I'll rebase this one on top and drop the fix hunks here, so it only contains the group-restriction feature.

Adds a new app config 'start_calls_groups' (JSON array of group ids,
empty by default). When set, only members of the configured groups can
start a call, while everyone can still chat and join ongoing calls.
This complements the existing 'start_calls' level and follows the
'start_conversations' pattern.

- Config::getAllowedStartCallGroupIds() / isNotAllowedToStartCalls()
- Enforced via Participant::canStartCall() so both the API enforcement
  (RestrictStartingCalls listener) and the clients (canStartCall room
  property) share the same source of truth
- Admin settings UI: group multiselect next to the existing options
- Deleted groups are cleaned from the setting
- Talk hash includes the new config to invalidate client state

Resolves nextcloud#17465

Signed-off-by: Pascal Kienast <info@pascalkienast.de>
Assisted-by: ClaudeCode:claude-fable-5
Assisted-by: OpenAI Codex:GPT-5
Unit tests for Config::isNotAllowedToStartCalls() and the adjusted
RestrictStartingCalls listener, plus an integration feature covering:
empty config (regression), allowed group member starting, non-member
being blocked, and non-member joining an ongoing call.

Resolves nextcloud#17465

Signed-off-by: Pascal Kienast <info@pascalkienast.de>
Assisted-by: ClaudeCode:claude-fable-5
@pascalkienast
pascalkienast force-pushed the enh/17465/restrict-call-start-to-groups branch from 2b9a73a to d2ec903 Compare July 15, 2026 22:39
@pascalkienast

Copy link
Copy Markdown
Contributor Author

@nickvergessen Since #18664 has now been merged, i have, as promised, rebased this PR and removed all of the underlying federation/HPB fix hunks here.

The diff now only contains the group-restriction feature, its admin UI and documentation, and the corresponding tests. I also updated the PR description.
This should now be ready for review whenever you have time. Thanks!

Comment thread lib/Config.php Resolved
Comment thread lib/Config.php Resolved
Use IAppConfig for the group array and keep participant-level call authorization in Participant::canStartCall.

Assisted-by: OpenAI Codex:GPT-5
Signed-off-by: Pascal Kienast <info@pascalkienast.de>

@Antreesy Antreesy left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked from the frontend side, no issues so far. Thanks for the contribution!
Leaving approval to backend developers

@nickvergessen nickvergessen added the AI assisted This PR contains AI-assisted commits label Jul 20, 2026
@nickvergessen
nickvergessen merged commit 9d8eec8 into nextcloud:main Jul 20, 2026
78 of 79 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI assisted This PR contains AI-assisted commits enhancement feature: api 🛠️ OCS API for conversations, chats and participants feature: call 📹 Voice and video calls feature: settings ⚙️ Settings and config related issues feedback-requested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Restrict video/audio call start to specific groups

3 participants