Skip to content

Commit

Permalink
BC-8345 - Add validation if value contains < directly followed by a s…
Browse files Browse the repository at this point in the history
…tring (#3584)
  • Loading branch information
bischofmax authored Feb 17, 2025
1 parent a9c4e02 commit 74db201
Show file tree
Hide file tree
Showing 14 changed files with 89 additions and 7 deletions.
5 changes: 2 additions & 3 deletions controllers/courses.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ router.post('/', (req, res, next) => {

api(req)
.post('/courses/', {
json: req.body, // TODO: sanitize
json: { ...req.body, name: req.body.name.trim() }, // TODO: sanitize
})
.then((course) => {
createEventsForCourse(req, res, course).then(() => {
Expand Down Expand Up @@ -882,10 +882,9 @@ router.patch('/:courseId', async (req, res, next) => {
// so temporarily add yourself to the list of teachers
req.body.teacherIds.push(currentUserId);
}

await deleteEventsForCourse(req, res, courseId);
await api(req).patch(`/courses/${courseId}`, {
json: req.body,
json: { ...req.body, name: req.body.name.trim() },
});
// due to eventual consistency we need to get the course again from server
// instead of using the response from patch
Expand Down
1 change: 1 addition & 0 deletions locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,7 @@
"noTopicFoundWithCode": "Es wurde kein Thema für diesen Code gefunden.",
"pageMoved": "Diese Seite wurde verschoben.",
"passwordsAreDifferent": "Passwörter stimmen nicht überein.",
"containsOpeningTag": "Bitte Leerzeichen nach Kleiner-als-Zeichen einfügen.",
"hasLowerCase": "Passwort muss Kleinbuchstaben enthalten.",
"hasUpperCase": "Passwort muss Großbuchstaben enthalten.",
"hasNumber": "Passwort muss eine Zahl enthalten.",
Expand Down
1 change: 1 addition & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,7 @@
"noTopicFoundWithCode": "No topic was found for this code.",
"pageMoved": "This page has been moved.",
"passwordsAreDifferent": "Passwords do not match.",
"containsOpeningTag": "Please insert a space after the less-than sign.",
"hasLowerCase": "Password must contain lowercase letters.",
"hasUpperCase": "Password must contain uppercase letters.",
"hasNumber": "Password must contain a number.",
Expand Down
1 change: 1 addition & 0 deletions locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1747,6 +1747,7 @@
"noTopicFoundWithCode": "No se ha encontrado ningún tema para este código.",
"pageMoved": "Esta página se ha movido.",
"passwordsAreDifferent": "Las contraseñas no coinciden.",
"containsOpeningTag": "Inserte un espacio después del signo menos-que.",
"hasLowerCase": "El contraseña debe contener letras minúsculas.",
"hasUpperCase": "El contraseña debe contener letras mayúsculas.",
"hasNumber": "La contraseña debe contener un número.",
Expand Down
1 change: 1 addition & 0 deletions locales/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@
"noTopicFoundWithCode": "Не знайдено теми для цього коду.",
"pageMoved": "Цю сторінку переміщено.",
"passwordsAreDifferent": "Паролі не збігаються.",
"containsOpeningTag": "Будь ласка, вставте пробіл після знаку менше.",
"hasLowerCase": "Пароль повинен містити малі літери.",
"hasUpperCase": "Пароль повинен містити великі літери.",
"hasNumber": "Пароль повинен містити цифру.",
Expand Down
8 changes: 8 additions & 0 deletions static/scripts/administration/school.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import validateInputOnOpeningTag from '../helpers/openingTagValidation';

function transformToBase64(imageSrc) {
const img = new Image();
const canvas = document.querySelector('#logo-canvas');
Expand Down Expand Up @@ -96,3 +98,9 @@ if (messengerInput && messengerSubOptions) {
setMessengerSubOptionsViability(event.target.checked);
});
}

$(document).ready(() => {
const schoolName = document.getElementsByName('name')[0];

if (schoolName) schoolName.addEventListener('keyup', () => validateInputOnOpeningTag(schoolName));
});
7 changes: 7 additions & 0 deletions static/scripts/course.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import validateInputOnOpeningTag from './helpers/openingTagValidation';

$(document).ready(() => {
const courseName = document.getElementsByName('name')[0];

if (courseName) courseName.addEventListener('keyup', () => validateInputOnOpeningTag(courseName));
});
4 changes: 0 additions & 4 deletions static/scripts/courses.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ $(document).ready(() => {
$('.safari-workaround').show();
}

$('.js-course-name-input').change(function courseNameInput() {
$(this).val($(this).val().trim());
});

$('.btn-hidden-toggle').click(function hiddenToggle(e) {
e.stopPropagation();
e.preventDefault();
Expand Down
20 changes: 20 additions & 0 deletions static/scripts/helpers/openingTagValidation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function containsOpeningTagFollowedByString(input) {
const regex = /<[^<\s]+/;
const result = regex.test(input);

return result;
};

export default function validateInputOnOpeningTag(input) {
// Firefox needs blur event to trigger validation
input.blur();
input.focus();

if (containsOpeningTagFollowedByString(input.value)) {
input.setCustomValidity($t('global.text.containsOpeningTag'));
} else {
input.setCustomValidity('');
}

input.reportValidity();
};
8 changes: 8 additions & 0 deletions static/scripts/homework/edit.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import validateInputOnOpeningTag from '../helpers/openingTagValidation';

const moment = require('moment-timezone');
const Mousetrap = require('../mousetrap/mousetrap');



window.addEventListener('DOMContentLoaded', () => {
const lang = $('html').attr('lang');
$.datetimepicker.setLocale(lang || 'de');
Expand Down Expand Up @@ -131,4 +135,8 @@ window.addEventListener('DOMContentLoaded', () => {
window.history.back();
}
});

const taskName = document.getElementsByName('name')[0];

if (taskName) taskName.addEventListener('keyup', () => validateInputOnOpeningTag(taskName));
});
7 changes: 7 additions & 0 deletions static/scripts/settings.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import './pwd.js';
import { validatePassword, validateConfirmationPassword } from './helpers/passwordValidations';
import validateInputOnOpeningTag from './helpers/openingTagValidation';


$(document).ready(function() {
Expand All @@ -11,6 +12,12 @@ $(document).ready(function() {
if (password) password.addEventListener('keyup', () => validatePassword(password));
if (confirm_password) confirm_password.addEventListener('keyup', () => validateConfirmationPassword(password, confirm_password));

const firstName = document.getElementsByName('firstName')[0];
if (firstName) firstName.addEventListener('keyup', () => validateInputOnOpeningTag(firstName));

const lastName = document.getElementsByName('lastName')[0];
if (lastName) lastName.addEventListener('keyup', () => validateInputOnOpeningTag(lastName));

// TODO: replace with something cooler
var reloadSite = function() {
delete_cookie("notificationPermission");
Expand Down
31 changes: 31 additions & 0 deletions static/scripts/topicEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,37 @@ import { arrayMove, SortableContainer, SortableElement, SortableHandle } from 'r
import shortid from 'shortid';
import ckeditorConfig from './ckeditor/ckeditor-config';
import showFallbackImageOnError from './helpers/showFallbackImageOnError';
import validateInputOnOpeningTag from './helpers/openingTagValidation';

$(document).ready(() => {
const lessonName = document.getElementsByName('name')[0];
if (lessonName) lessonName.addEventListener('keyup', () => validateInputOnOpeningTag(lessonName));

document.querySelectorAll('[name^="contents["][name$="[title]"]')
.forEach((element) => element.addEventListener('keyup', () => validateInputOnOpeningTag(element)));

// Observers if new content blocks are added to the page and ads the validation to the title input
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length) {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === 1) {
const inputs = node.querySelectorAll('[name^="contents["][name$="[title]"]');

inputs.forEach((input) => {
input.addEventListener('keyup', () => validateInputOnOpeningTag(input));
});
}
});
}
});
});

observer.observe(document.body, {
childList: true,
subtree: true,
});
});

/**
* A wrapper for each block including a title field, remove, sortable, ...
Expand Down
1 change: 1 addition & 0 deletions views/courses/create-course.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<script src="{{getAssetPath '/scripts/jquery/datetimepicker-easy.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/moment/moment.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/courses.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/course.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/coursesTimes.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/spectrum/spectrum.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/spectrum/init.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
Expand Down
1 change: 1 addition & 0 deletions views/courses/edit-course.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<script src="{{getAssetPath '/scripts/jquery/datetimepicker-easy.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/moment/moment.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/courses.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/course.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/coursesTimes.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/spectrum/spectrum.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
<script src="{{getAssetPath '/scripts/spectrum/init.js'}}" type="text/javascript" nonce="{{nonceValue}}" defer></script>
Expand Down

0 comments on commit 74db201

Please sign in to comment.