From 1e150142c1339848f09984a8d277b8f13d5132a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Molina?= Date: Wed, 22 Apr 2026 20:21:33 +0200 Subject: [PATCH] feat: add dynamic passcode length --- vc_zoom/README.md | 1 + vc_zoom/indico_vc_zoom/plugin.py | 13 +++++++++---- vc_zoom/indico_vc_zoom/util.py | 6 +++--- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index 263d821c4..e06daa6e0 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -175,6 +175,7 @@ These are the most relevant configuration options: * **Notification email addresses** - Additional e-mails which will receive notifications * **E-mail domains** - List of e-mail domains which can be used for the Zoom API (e.g. `cern.ch`) * **Webhook Secret Token** (optional) - the token which Zoom requests will authenticate with (get it from Zoom Marketplace) + * **Passcode length** - Length of auto-generated Zoom meeting passcodes (default 8, allowed range 8-10) * **Allow automatic registration** - Enable this to allow event managers to opt-in to automatic Zoom registration on individual meetings/webinars. Requires the registration-related scopes listed below. When enabled, a per-room "Automatic registration" toggle becomes available in the meeting settings. diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 87b677135..1b701dcfd 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -9,9 +9,9 @@ from markupsafe import escape from requests.exceptions import HTTPError from sqlalchemy.orm.attributes import flag_modified -from wtforms.fields import BooleanField, TextAreaField, URLField +from wtforms.fields import BooleanField, IntegerField, TextAreaField, URLField from wtforms.fields.simple import StringField -from wtforms.validators import URL, DataRequired, Optional, ValidationError +from wtforms.validators import URL, DataRequired, NumberRange, Optional, ValidationError from indico.core import signals from indico.core.auth import multipass @@ -42,7 +42,7 @@ from indico_vc_zoom.notifications import notify_host_start_url from indico_vc_zoom.task import refresh_meetings from indico_vc_zoom.util import (UserLookupMode, ZoomMeetingType, fetch_zoom_meeting, find_enterprise_email, - gen_random_password, get_alt_host_emails, get_schedule_args, get_url_data_args, + gen_random_passcode, get_alt_host_emails, get_schedule_args, get_url_data_args, process_alternative_hosts, update_zoom_meeting) @@ -92,6 +92,7 @@ def _get_missing_auto_registration_scopes(granted_scopes, *, allow_webinars): class PluginSettingsForm(VCPluginSettingsFormBase): _fieldsets = [ (_('API Credentials'), ['account_id', 'client_id', 'client_secret', 'webhook_token']), + (_('Security'), ['passcode_length']), (_('Zoom Account'), ['user_lookup_mode', 'email_domains', 'authenticators', 'enterprise_domain', 'allow_webinars', 'allow_language_interpretation', 'allow_auto_register', 'phone_link']), (_('Room Settings'), ['mute_audio', 'mute_host_video', 'mute_participant_video', 'join_before_host', @@ -107,6 +108,9 @@ class PluginSettingsForm(VCPluginSettingsFormBase): description=_('Specify the "Secret Token" of your Zoom Webhook if you want ' 'live updates in case of modified/deleted Zoom meetings.')) + passcode_length = IntegerField(_('Passcode length'), [DataRequired(), NumberRange(min=8, max=10)], + description=_('Length of auto-generated Zoom meeting passcodes')) + user_lookup_mode = IndicoEnumSelectField(_('User lookup mode'), [DataRequired()], enum=UserLookupMode, description=_('Specify how Indico should look up the zoom user that ' 'corresponds to an Indico user.')) @@ -235,6 +239,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'client_id': '', 'client_secret': '', 'webhook_token': '', + 'passcode_length': 8, 'user_lookup_mode': UserLookupMode.email_domains, 'email_domains': [], 'authenticators': [], @@ -307,7 +312,7 @@ def create_form(self, event, existing_vc_room=None, existing_event_vc_room=None) form.host_choice.render_kw = {'disabled': True} form.host_user.render_kw = {'disabled': True} elif not form.is_submitted(): - form.password.data = gen_random_password() + form.password.data = gen_random_passcode(self.settings.get('passcode_length')) return form def get_extra_delete_msg(self, vc_room, event_vc_room): diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 68fc92310..752bd6a25 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -103,9 +103,9 @@ def find_enterprise_email(user): return next((email for email in iter_user_emails(user) if client.get_user(email, silent=True)), None) -def gen_random_password(): - """Generate a random 8-character-long numeric string.""" - return ''.join(secrets.choice(string.digits) for _ in range(8)) +def gen_random_passcode(length=8): + """Generate a random numeric string.""" + return ''.join(secrets.choice(string.digits) for _ in range(length)) def fetch_zoom_meeting(vc_room, client=None, *, _is_webinar=False):