Enhance security and validation across multiple routes:
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m25s
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m25s
- Escape XML and HTML special characters to prevent injection attacks. - Implement rate limiting for various endpoints to mitigate abuse. - Add validation for email formats, password lengths, and field limits. - Ensure proper access control for recordings and room management.
This commit is contained in:
@@ -81,10 +81,16 @@ export async function createMeeting(room, logoutURL, loginURL = null, presentati
|
||||
params.lockSettingsLockOnJoin = 'true';
|
||||
}
|
||||
|
||||
// Build optional presentation XML body
|
||||
const xmlBody = presentationUrl
|
||||
? `<modules><module name="presentation"><document url="${presentationUrl}" /></module></modules>`
|
||||
: null;
|
||||
// Build optional presentation XML body – escape URL to prevent XML injection
|
||||
let xmlBody = null;
|
||||
if (presentationUrl) {
|
||||
const safeUrl = presentationUrl
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
xmlBody = `<modules><module name="presentation"><document url="${safeUrl}" /></module></modules>`;
|
||||
}
|
||||
|
||||
return apiCall('create', params, xmlBody);
|
||||
}
|
||||
@@ -132,6 +138,17 @@ export async function getRecordings(meetingID) {
|
||||
return Array.isArray(recordings) ? recordings : [recordings];
|
||||
}
|
||||
|
||||
export async function getRecordingByRecordId(recordID) {
|
||||
const result = await apiCall('getRecordings', { recordID });
|
||||
if (result.returncode !== 'SUCCESS' || !result.recordings) {
|
||||
return null;
|
||||
}
|
||||
const recordings = result.recordings.recording;
|
||||
if (!recordings) return null;
|
||||
const arr = Array.isArray(recordings) ? recordings : [recordings];
|
||||
return arr[0] || null;
|
||||
}
|
||||
|
||||
export async function deleteRecording(recordID) {
|
||||
return apiCall('deleteRecordings', { recordID });
|
||||
}
|
||||
|
||||
@@ -2,6 +2,17 @@ import nodemailer from 'nodemailer';
|
||||
|
||||
let transporter;
|
||||
|
||||
// Escape HTML special characters to prevent injection in email bodies
|
||||
function escapeHtml(str) {
|
||||
if (!str) return '';
|
||||
return String(str)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''');
|
||||
}
|
||||
|
||||
export function initMailer() {
|
||||
const host = process.env.SMTP_HOST;
|
||||
const port = parseInt(process.env.SMTP_PORT || '587', 10);
|
||||
@@ -44,6 +55,8 @@ export async function sendVerificationEmail(to, name, verifyUrl, appName = 'Redl
|
||||
}
|
||||
|
||||
const from = process.env.SMTP_FROM || process.env.SMTP_USER;
|
||||
const safeName = escapeHtml(name);
|
||||
const safeAppName = escapeHtml(appName);
|
||||
|
||||
await transporter.sendMail({
|
||||
from: `"${appName}" <${from}>`,
|
||||
@@ -51,7 +64,7 @@ export async function sendVerificationEmail(to, name, verifyUrl, appName = 'Redl
|
||||
subject: `${appName} – Verify your email`,
|
||||
html: `
|
||||
<div style="font-family:Arial,sans-serif;max-width:520px;margin:0 auto;padding:32px;background:#1e1e2e;color:#cdd6f4;border-radius:12px;">
|
||||
<h2 style="color:#cba6f7;margin-top:0;">Hey ${name} 👋</h2>
|
||||
<h2 style="color:#cba6f7;margin-top:0;">Hey ${safeName} 👋</h2>
|
||||
<p>Please verify your email address by clicking the button below:</p>
|
||||
<p style="text-align:center;margin:28px 0;">
|
||||
<a href="${verifyUrl}"
|
||||
@@ -61,7 +74,7 @@ export async function sendVerificationEmail(to, name, verifyUrl, appName = 'Redl
|
||||
</p>
|
||||
<p style="font-size:13px;color:#7f849c;">
|
||||
Or copy this link in your browser:<br/>
|
||||
<a href="${verifyUrl}" style="color:#89b4fa;word-break:break-all;">${verifyUrl}</a>
|
||||
<a href="${verifyUrl}" style="color:#89b4fa;word-break:break-all;">${escapeHtml(verifyUrl)}</a>
|
||||
</p>
|
||||
<p style="font-size:13px;color:#7f849c;">This link is valid for 24 hours.</p>
|
||||
<hr style="border:none;border-top:1px solid #313244;margin:24px 0;"/>
|
||||
@@ -86,6 +99,11 @@ export async function sendFederationInviteEmail(to, name, fromUser, roomName, me
|
||||
if (!transporter) return; // silently skip if SMTP not configured
|
||||
|
||||
const from = process.env.SMTP_FROM || process.env.SMTP_USER;
|
||||
const safeName = escapeHtml(name);
|
||||
const safeFromUser = escapeHtml(fromUser);
|
||||
const safeRoomName = escapeHtml(roomName);
|
||||
const safeMessage = message ? escapeHtml(message) : null;
|
||||
const safeAppName = escapeHtml(appName);
|
||||
|
||||
await transporter.sendMail({
|
||||
from: `"${appName}" <${from}>`,
|
||||
@@ -93,12 +111,12 @@ export async function sendFederationInviteEmail(to, name, fromUser, roomName, me
|
||||
subject: `${appName} – Meeting invitation from ${fromUser}`,
|
||||
html: `
|
||||
<div style="font-family:Arial,sans-serif;max-width:520px;margin:0 auto;padding:32px;background:#1e1e2e;color:#cdd6f4;border-radius:12px;">
|
||||
<h2 style="color:#cba6f7;margin-top:0;">Hey ${name} 👋</h2>
|
||||
<p>You have received a meeting invitation from <strong style="color:#cdd6f4;">${fromUser}</strong>.</p>
|
||||
<h2 style="color:#cba6f7;margin-top:0;">Hey ${safeName} 👋</h2>
|
||||
<p>You have received a meeting invitation from <strong style="color:#cdd6f4;">${safeFromUser}</strong>.</p>
|
||||
<div style="background:#313244;border-radius:8px;padding:16px;margin:20px 0;">
|
||||
<p style="margin:0 0 8px 0;font-size:13px;color:#7f849c;">Room:</p>
|
||||
<p style="margin:0;font-size:16px;font-weight:bold;color:#cdd6f4;">${roomName}</p>
|
||||
${message ? `<p style="margin:12px 0 0 0;font-size:13px;color:#a6adc8;font-style:italic;">"${message}"</p>` : ''}
|
||||
<p style="margin:0;font-size:16px;font-weight:bold;color:#cdd6f4;">${safeRoomName}</p>
|
||||
${safeMessage ? `<p style="margin:12px 0 0 0;font-size:13px;color:#a6adc8;font-style:italic;">"${safeMessage}"</p>` : ''}
|
||||
</div>
|
||||
<p style="text-align:center;margin:28px 0;">
|
||||
<a href="${inboxUrl}"
|
||||
|
||||
Reference in New Issue
Block a user