From 4656ba117658b17d53e39f1c25630420a69430f7 Mon Sep 17 00:00:00 2001 From: Markos Gogoulos Date: Thu, 12 Feb 2026 14:24:45 +0200 Subject: [PATCH] awesome --- .../filter/mediacms/classes/text_filter.php | 4 ++ .../filter/mediacms/launch.php | 50 +++++++++++++------ lti/views.py | 39 +++++++++++++-- 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/lms-plugins/mediacms-moodle/filter/mediacms/classes/text_filter.php b/lms-plugins/mediacms-moodle/filter/mediacms/classes/text_filter.php index 90ae8071..b4070341 100644 --- a/lms-plugins/mediacms-moodle/filter/mediacms/classes/text_filter.php +++ b/lms-plugins/mediacms-moodle/filter/mediacms/classes/text_filter.php @@ -103,6 +103,10 @@ class text_filter extends \core_filters\text_filter { // Extract additional embed parameters from the URL $embed_params = []; $full_url = $matches[1]; + + // Decode HTML entities (& -> &) before parsing + $full_url = html_entity_decode($full_url, ENT_QUOTES | ENT_HTML5); + $parsed_url = parse_url($full_url); if (isset($parsed_url['query'])) { diff --git a/lms-plugins/mediacms-moodle/filter/mediacms/launch.php b/lms-plugins/mediacms-moodle/filter/mediacms/launch.php index 25d61bd4..80e1ec4c 100644 --- a/lms-plugins/mediacms-moodle/filter/mediacms/launch.php +++ b/lms-plugins/mediacms-moodle/filter/mediacms/launch.php @@ -137,20 +137,20 @@ $instance = $DB->get_record('lti', ['id' => $cm->instance], '*', MUST_EXIST); // Override with our media token for THIS launch only (doesn't save to DB) $custom_params = ["media_friendly_token=" . $mediatoken]; -// Add embed parameters if provided -if (!empty($showTitle)) { +// Add embed parameters if provided (check !== '' instead of !empty() because '0' is a valid value) +if ($showTitle !== '') { $custom_params[] = "embed_show_title=" . $showTitle; } -if (!empty($showRelated)) { +if ($showRelated !== '') { $custom_params[] = "embed_show_related=" . $showRelated; } -if (!empty($showUserAvatar)) { +if ($showUserAvatar !== '') { $custom_params[] = "embed_show_user_avatar=" . $showUserAvatar; } -if (!empty($linkTitle)) { +if ($linkTitle !== '') { $custom_params[] = "embed_link_title=" . $linkTitle; } -if (!empty($startTime)) { +if ($startTime !== '') { $custom_params[] = "embed_start_time=" . $startTime; } @@ -165,20 +165,20 @@ $page_params = [ 'height' => $height ]; -// Add embed parameters to page URL if provided -if (!empty($showTitle)) { +// Add embed parameters to page URL if provided (check !== '' because '0' is valid) +if ($showTitle !== '') { $page_params['showTitle'] = $showTitle; } -if (!empty($showRelated)) { +if ($showRelated !== '') { $page_params['showRelated'] = $showRelated; } -if (!empty($showUserAvatar)) { +if ($showUserAvatar !== '') { $page_params['showUserAvatar'] = $showUserAvatar; } -if (!empty($linkTitle)) { +if ($linkTitle !== '') { $page_params['linkTitle'] = $linkTitle; } -if (!empty($startTime)) { +if ($startTime !== '') { $page_params['t'] = $startTime; } @@ -193,10 +193,28 @@ $typeconfig = lti_get_type_type_config($type->id); // Initiate LTI Login with proper cmid (for permissions) and custom token $content = lti_initiate_login($course->id, $dummy_cmid, $instance, $typeconfig, null, $instance->name); -// CRITICAL: Inject media_token as hidden field in OIDC form -// MediaCMS will encode it in state and inject into custom claims (fallback mechanism) -$media_token_field = ''; -$content = str_replace('', $media_token_field . '', $content); +// CRITICAL: Inject media_token and embed parameters as hidden fields in OIDC form +// MediaCMS will encode them in state and inject into custom claims (fallback mechanism) +$hidden_fields = ''; + +// Add embed parameters as hidden fields +if ($showTitle !== '') { + $hidden_fields .= ''; +} +if ($showRelated !== '') { + $hidden_fields .= ''; +} +if ($showUserAvatar !== '') { + $hidden_fields .= ''; +} +if ($linkTitle !== '') { + $hidden_fields .= ''; +} +if ($startTime !== '') { + $hidden_fields .= ''; +} + +$content = str_replace('', $hidden_fields . '', $content); echo $OUTPUT->header(); echo $content; diff --git a/lti/views.py b/lti/views.py index 75408ef3..2b8065d6 100644 --- a/lti/views.py +++ b/lti/views.py @@ -81,6 +81,13 @@ class OIDCLoginView(View): cmid = request.GET.get('cmid') or request.POST.get('cmid') media_token = request.GET.get('media_token') or request.POST.get('media_token') + # Extract embed parameters from request + embed_show_title = request.GET.get('embed_show_title') or request.POST.get('embed_show_title') + embed_show_related = request.GET.get('embed_show_related') or request.POST.get('embed_show_related') + embed_show_user_avatar = request.GET.get('embed_show_user_avatar') or request.POST.get('embed_show_user_avatar') + embed_link_title = request.GET.get('embed_link_title') or request.POST.get('embed_link_title') + embed_start_time = request.GET.get('embed_start_time') or request.POST.get('embed_start_time') + if not all([target_link_uri, iss, client_id]): return JsonResponse({'error': 'Missing required OIDC parameters'}, status=400) @@ -114,6 +121,18 @@ class OIDCLoginView(View): if media_token: state_data['media_token'] = media_token + # Add embed parameters to state + if embed_show_title: + state_data['embed_show_title'] = embed_show_title + if embed_show_related: + state_data['embed_show_related'] = embed_show_related + if embed_show_user_avatar: + state_data['embed_show_user_avatar'] = embed_show_user_avatar + if embed_link_title: + state_data['embed_link_title'] = embed_link_title + if embed_start_time: + state_data['embed_start_time'] = embed_start_time + # Encode as base64 URL-safe string state = base64.urlsafe_b64encode(json.dumps(state_data).encode()).decode().rstrip('=') @@ -217,8 +236,9 @@ class LaunchView(View): error_message = '' claims = {} - # Extract media_token from state parameter if present (for filter launches) + # Extract media_token and embed parameters from state parameter if present (for filter launches) media_token_from_state = None + embed_params_from_state = {} state = request.POST.get('state') if state: try: @@ -232,6 +252,11 @@ class LaunchView(View): state_decoded = base64.urlsafe_b64decode(state_padded.encode()).decode() state_data = json.loads(state_decoded) media_token_from_state = state_data.get('media_token') + + # Extract embed parameters from state + for key in ['embed_show_title', 'embed_show_related', 'embed_show_user_avatar', 'embed_link_title', 'embed_start_time']: + if key in state_data: + embed_params_from_state[key] = state_data[key] except Exception: pass @@ -265,15 +290,21 @@ class LaunchView(View): launch_data = message_launch.get_launch_data() claims = self.sanitize_claims(launch_data) - # Extract custom claims and inject media_token from state if present + # Extract custom claims and inject media_token and embed params from state if present try: custom_claims = launch_data.get('https://purl.imsglobal.org/spec/lti/claim/custom', {}) # Inject media_token from state if present (for filter launches) if media_token_from_state and not custom_claims.get('media_friendly_token'): custom_claims['media_friendly_token'] = media_token_from_state - # Update launch_data with the modified custom claims - launch_data['https://purl.imsglobal.org/spec/lti/claim/custom'] = custom_claims + + # Inject embed parameters from state if present + for key, value in embed_params_from_state.items(): + if key not in custom_claims: + custom_claims[key] = value + + # Update launch_data with the modified custom claims + launch_data['https://purl.imsglobal.org/spec/lti/claim/custom'] = custom_claims except Exception: custom_claims = {}