fix (LAD/cluster): Enable LearningDashboard cookie support across different subdomains (#21518)
* Enable LearningDashboard cookie support across different subdomains. After a meeting ends, the client sets a cookie `ld-${meetingId}` with a token used to retrieve meeting data in JSON format. The Learning Dashboard needs access to this cookie to obtain the token. The issue occurs in a Cluster setup where the Dashboard is hosted on a different subdomain, preventing it from accessing the cookie. To resolve this, the client will set the cookie using the root domain (excluding the subdomain). This allows the cookie to be accessible from any subdomain. * lint fixes * Update bigbluebutton-html5/imports/ui/components/meeting-ended/service.ts Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com> --------- Co-authored-by: Anton Georgiev <antobinary@users.noreply.github.com>
This commit is contained in:
parent
03a6901e52
commit
63bf4f35bc
@ -284,7 +284,7 @@ const MeetingEnded: React.FC<MeetingEndedProps> = ({
|
|||||||
{
|
{
|
||||||
learningDashboardAccessToken && isModerator
|
learningDashboardAccessToken && isModerator
|
||||||
// Always set cookie in case Dashboard is already opened
|
// Always set cookie in case Dashboard is already opened
|
||||||
&& setLearningDashboardCookie(learningDashboardAccessToken, meetingId) === true
|
&& setLearningDashboardCookie(learningDashboardAccessToken, meetingId, learningDashboardBase) === true
|
||||||
? (
|
? (
|
||||||
<Styled.Text>
|
<Styled.Text>
|
||||||
<Styled.MeetingEndedButton
|
<Styled.MeetingEndedButton
|
||||||
|
@ -24,6 +24,43 @@ export const MeetingEndedTable = {
|
|||||||
ENDED_DUE_TO_SERVICE_INTERRUPTION: 'ENDED_DUE_TO_SERVICE_INTERRUPTION',
|
ENDED_DUE_TO_SERVICE_INTERRUPTION: 'ENDED_DUE_TO_SERVICE_INTERRUPTION',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const findCommonDomain = (url1: string, url2: string): string => {
|
||||||
|
// Helper function to extract domain parts in reverse order
|
||||||
|
const getDomainParts = (url: string): string[] => {
|
||||||
|
try {
|
||||||
|
const { hostname } = new URL(url);
|
||||||
|
return hostname.split('.').reverse();
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`Invalid URL format: ${url}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const domain1Parts: string[] = getDomainParts(url1);
|
||||||
|
const domain2Parts: string[] = getDomainParts(url2);
|
||||||
|
|
||||||
|
// Find common parts starting from the end (TLD)
|
||||||
|
const commonParts: string[] = [];
|
||||||
|
const minLength: number = Math.min(domain1Parts.length, domain2Parts.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < minLength; i += 1) {
|
||||||
|
if (domain1Parts[i] === domain2Parts[i]) {
|
||||||
|
commonParts.push(domain1Parts[i]);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the common parts in correct order
|
||||||
|
if (commonParts.length > 0) {
|
||||||
|
return commonParts.reverse().join('.');
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
} catch (error) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const openLearningDashboardUrl = (
|
export const openLearningDashboardUrl = (
|
||||||
accessToken: string,
|
accessToken: string,
|
||||||
mId: string,
|
mId: string,
|
||||||
@ -31,18 +68,28 @@ export const openLearningDashboardUrl = (
|
|||||||
learningDashboardBase: string,
|
learningDashboardBase: string,
|
||||||
lang: string,
|
lang: string,
|
||||||
) => {
|
) => {
|
||||||
if (accessToken && setLearningDashboardCookie(accessToken, mId)) {
|
if (accessToken && setLearningDashboardCookie(accessToken, mId, learningDashboardBase)) {
|
||||||
window.open(`${learningDashboardBase}/?meeting=${mId}&lang=${lang}`, '_blank');
|
window.open(`${learningDashboardBase}/?meeting=${mId}&lang=${lang}`, '_blank');
|
||||||
} else {
|
} else {
|
||||||
window.open(`${learningDashboardBase}/?meeting=${mId}&sessionToken=${sToken}&lang=${lang}`, '_blank');
|
window.open(`${learningDashboardBase}/?meeting=${mId}&sessionToken=${sToken}&lang=${lang}`, '_blank');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setLearningDashboardCookie = (accessToken: string, mId: string) => {
|
export const setLearningDashboardCookie = (accessToken: string, mId: string, learningDashboardBase: string) => {
|
||||||
if (accessToken !== null) {
|
if (accessToken !== null) {
|
||||||
const lifetime = new Date();
|
const lifetime = new Date();
|
||||||
lifetime.setTime(lifetime.getTime() + (3600000)); // 1h (extends 7d when open Dashboard)
|
lifetime.setTime(lifetime.getTime() + (3600000)); // 1h (extends 7d when open Dashboard)
|
||||||
document.cookie = `ld-${mId}=${accessToken}; expires=${lifetime.toUTCString()}; path=/`;
|
let cookieString = `ld-${mId}=${accessToken}; expires=${lifetime.toUTCString()}; path=/`;
|
||||||
|
|
||||||
|
// In a cluster setup it will be necessary to specify the root domain
|
||||||
|
// because the Dashboard might be in a different subdomain
|
||||||
|
if (learningDashboardBase && learningDashboardBase.startsWith('http')) {
|
||||||
|
const commonDomain = findCommonDomain(learningDashboardBase, window.location.href);
|
||||||
|
if (commonDomain !== '') {
|
||||||
|
cookieString += `;domain=${commonDomain}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.cookie = cookieString;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
Loading…
Reference in New Issue
Block a user